home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / para.lha / para / para.el < prev    next >
Text File  |  1991-04-18  |  102KB  |  2,753 lines

  1. ;;; para-mode
  2.  
  3. ;;; Copyright (C) 1989, 1990, 1991 Free Software Foundation
  4. ;;; ALPHA test version; not for widespead distribution.
  5. ;;; Robert J. Chassell
  6. ;;; bugs to bob@ai.mit.edu
  7. ;;;
  8. ;;; Known bug: para-add-node deletes the detailed part of a master
  9. ;;;            menu if the added node is a chapter.  Will need to
  10. ;;;            modify para-insert-update-pointers-&-menu, using ideas
  11. ;;;            from para-make-master-menu.
  12. ;;;
  13. ;;; Change Log ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  14. ;;;
  15. ;;; Version 0.27
  16. ;;; 17 apr 91 - Defined `para-main-menu-buffer-name' global variable
  17. ;;;             with default value of empty string.  `para-xref' now
  18. ;;;             works even without listing the main menu.
  19. ;;;
  20. ;;; Version 0.26
  21. ;;;  5 Apr 91 - Added `para-scroll-down' (bound to DEL); works
  22. ;;;             parallel to `para-scroll-up' (bound to SPC).
  23. ;;;
  24. ;;; Version 0.25
  25. ;;;  3 Apr 91 - `para-make-file' rewritten.
  26. ;;;
  27. ;;; Version 0.24
  28. ;;; 27 Mar 91 - Indexing commands defined.
  29. ;;;
  30. ;;; Version 0.23
  31. ;;; 25 Mar 91 - `para-menu-explode' defined; forgot to include it before.
  32. ;;;              `para-preceding-node-type' returns "top" if in top node
  33. ;;;              and current node if on node line.  `para-add-node'
  34. ;;;              changed to work with new `para-preceding-node-type'.
  35. ;;;              `para-search' defined; searches forward for regexp.
  36. ;;;
  37. ;;; Version 0.22
  38. ;;; 19 Mar 91 - Rewrote `para-extract-menu-name' to use
  39. ;;;             `para-extract-menu-node-name' which returns nodename.
  40. ;;;             This makes mouse menu selection possible in X.
  41. ;;;
  42. ;;; Version 0.21
  43. ;;;  4 Mar 91 - Added `para-history' to `para-goto' when using tag table.
  44. ;;;             Added `para-tagify' and its utility function,
  45. ;;;             `para-clean-name' so tag tables can be made.
  46. ;;;             Removed infinite loop from `para-last'.
  47. ;;;             Added new movement commands: para-scroll-up,
  48. ;;;             para-top-node, para-final,
  49. ;;;             para-goto-previous-node-in-sequence,
  50. ;;;             para-goto-next-node-in-sequence
  51. ;;;
  52. ;;; Version 0.20
  53. ;;; 26 Feb 91 - Rewrote much of code.  No longer dependent on `infosim.el'
  54. ;;;
  55. ;;; Version 0.10
  56. ;;; 12 Feb 91 - Revised all keybindings to be consistent with Texinfo mode.
  57. ;;;             Merged bug fixes and new menu and file finding commands.
  58. ;;;             Revised `para.texinfo' doc file.
  59. ;;;
  60. ;;; <other change logs removed>
  61. ;;;
  62. ;;; Version 0.01
  63. ;;; 17 Dec 1989 - 
  64. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  65.  
  66.  
  67. ;;; What is Para mode?
  68.  
  69. ;;; Para mode is an extension of Texinfo and Infosim mode that
  70. ;;; includes some hypertext-like features.  I chose the name `Para
  71. ;;; mode' (from the Greek word for `beyond') to suggest that it is
  72. ;;; `beyond' Texinfo mode or Infosim mode, but not to claim that it is
  73. ;;; a full-fledged hypertext system.  Eventually, Para mode should be
  74. ;;; merged into Texinfo mode.
  75.  
  76. ;;; Para mode was inspired by Infosim mode, which was written by
  77. ;;; Matthew P Wiener.
  78.  
  79. ;;; This code is in `alpha-test'.  Please do not distribute it widely.
  80.  
  81.  
  82. ;;; Summary list of Para mode commands
  83. ;     C-c C-p f       para-make-file
  84. ;     C-c C-p C-q     para-quit
  85. ;     C-c C-p a       para-add-node
  86. ;     C-c C-p i       para-insert-menu
  87. ;     C-c C-p e       para-menu-explode
  88. ;     C-c C-p n       para-narrow-to-node
  89. ;     C-c C-p m       para-make-master-menu           (primary updating 
  90. ;                                                      command)
  91. ;     C-c C-p t       para-tagify                     (for faster movement
  92. ;                                                      in large files)
  93. ;
  94. ; Directory listing and related movement commands
  95. ;     C-c C-p d       para-directory
  96. ;     C-c C-p l       para-list-visited-nodes
  97. ;     C-c C-p C-m     para-main-menu-goto-node        (these commands parallel
  98. ;     C-c C-p C-m     para-goto-visited-node           each other in 
  99. ;     C-c C-p C-m     para-menu                        different buffers)
  100. ; Other movement commands
  101. ;
  102. ;     C-c C-p C-b     para-beginning                   (beginning of file)
  103. ;     C-c C-p C-<     para-top-node
  104. ;     C-c C-p C->     para-final                       (last node in file)
  105. ;
  106. ;     C-c C-p C-u     para-up
  107. ;     C-c C-p C-p     para-prev
  108. ;     C-c C-p C-[     para-goto-previous-node-in-sequence
  109. ;     C-c C-p C-n     para-next
  110. ;     C-c C-p C-]     para-goto-next-node-in-sequence
  111. ;     C-c C-p RET     para-menu        (i.e., key chord is `C-p C-c C-m')
  112. ;     C-c C-p C-l     para-last
  113. ;     C-c C-p C-g     para-goto-node
  114. ;     C-c C-p C-f     para-follow
  115. ;     C-c C-p 1       para-menu-1      go to the node of the first menu 
  116. ;                                         item, etc., up to `9'
  117. ;     C-c C-p C-s     para-search
  118. ; Cross reference creation commands
  119. ;
  120. ;     C-c C-p r       para-main-menu-buffer-xref      (these commands parallel
  121. ;     C-c C-p r       para-visited-xref                each other in 
  122. ;     C-c C-p r       para-xref                        different buffers)
  123. ;
  124. ; Indexing commands
  125. ;
  126. ;     C-c C-x c       para-index-concept             (these commands insert
  127. ;     C-c C-x f       para-index-function             index entries)
  128. ;     C-c C-x k       para-index-keystroke
  129. ;     C-c C-x p       para-index-program
  130. ;     C-c C-x t       para-index-datatype
  131. ;     C-c C-x v       para-index-variable
  132. ;
  133. ;     C-c C-x x       para-insert-index              (cause @printindex
  134. ;                                                     to insert indices)
  135. ; Texinfo updating commands  (other Texinfo commands work also) 
  136. ;
  137. ;     C-c C-u C-e     texinfo-every-node-update
  138. ;     C-c C-u C-a     texinfo-all-menus-update
  139. ;
  140.  
  141. ;;; Load files
  142.  
  143. ;;; The standard Emacs 18 distribution loads version 1 Texinfo files.
  144. ;;; Para mode requires version 2 Texinfo files.
  145.  
  146. ;;; To ensure that you load version 2 Texinfo files, you must list the
  147. ;;; directory containing the version 2 Texinfo files in your load path
  148. ;;; before you list the directory containing the version 1 files.  You
  149. ;;; could do this by setting your load path in your `.emacs' file in a
  150. ;;; manner somewhat similar to the following: (If the first element of
  151. ;;; the load path is nil, it signifies the current directory.)
  152.  
  153. ;;; (setq load-path '(nil "/u/texinfo2" "/u/para" "/usr/local/lib/emacs/lisp")
  154.  
  155. ;;; After setting the load path, you may load the necessary Texinfo
  156. ;;; files the following commands:
  157.  
  158. ;(load "texinfo")
  159. ;(load "texnfo-upd")
  160.  
  161. ;;; Or you may use `require' commands in this `para.el' file, which is
  162. ;;; more elegant:
  163.  
  164. (require 'texinfo)
  165. (require 'texnfo-upd)
  166.  
  167. (message "Loading Para mode ... ")
  168. ;;; (Place `provide' at end of file.)
  169.  
  170.  
  171. ;;; Syntax table
  172.  
  173. (defvar para-mode-syntax-table nil)
  174.  
  175. (if para-mode-syntax-table nil          ; based in Infosim mode
  176.   (setq para-mode-syntax-table (make-syntax-table))
  177.   (modify-syntax-entry ?\" " " para-mode-syntax-table)
  178.   (modify-syntax-entry ?\\ " " para-mode-syntax-table)
  179.   (modify-syntax-entry ?@ "\\" para-mode-syntax-table)
  180.   (modify-syntax-entry ?\^q "\\" para-mode-syntax-table)
  181.   (modify-syntax-entry ?\[ "(]" para-mode-syntax-table)
  182.   (modify-syntax-entry ?\] ")[" para-mode-syntax-table)
  183.   (modify-syntax-entry ?{ "(}" para-mode-syntax-table)
  184.   (modify-syntax-entry ?} "){" para-mode-syntax-table)
  185.   (modify-syntax-entry ?\' "w" para-mode-syntax-table))
  186.  
  187.  
  188. ;;; Keybindings
  189.  
  190. ;;; Keybindings are compatible with Texinfo mode,
  191. ;;; which are defined in `texinfo.el'.
  192.  
  193.     ; TeX commands              prefix key: `C-c C-t'
  194.     ; Elisp formatting commands prefix key: `C-c C-e'
  195.     ; C code commands           prefix key: `C-c C-m'
  196.     ; Updating commands         prefix key: `C-c C-u'
  197.     ; String insertion commands prefix key: `C-c C-c'
  198.  
  199.     ; Para indexing commands    prefix key: `C-c C-x'
  200.     ; Para mode general         prefix key: `C-c C-p'
  201.  
  202. ;;; Para mode keys should use a `C-c C-p' prefix, except for
  203. ;;; indexing commands and those keys that have special
  204. ;;; meaning only in the upper left-hand corner of the window, or in
  205. ;;; read-only buffers.
  206.  
  207. ;;; The Para mode keybinding convention is that movement commands use
  208. ;;; only control keys and insertion commands use prefix plus regular
  209. ;;; key, like the Texinfo string insertion commands.
  210.  
  211. (defvar para-mode-map nil "Keymap for Para mode.")
  212.  
  213. ;;; !!! remove this setq after finishing testing!
  214. (setq para-mode-map nil)
  215.  
  216. (if para-mode-map nil
  217.  
  218. ;;; Provide Texinfo mode keybindings;
  219. ;;; must be from Texinfo version 2.
  220.   (setq para-mode-map (copy-keymap texinfo-mode-map))
  221.  
  222.   (define-key para-mode-map "\t" 'tab-to-tab-stop)
  223.  
  224. ;;; The following keybindings apply only when the cursor is in the
  225. ;;; upper left hand corner of the window.
  226.   (define-key para-mode-map " " 'para-@)
  227.   (define-key para-mode-map "0" 'para-@)
  228.   (define-key para-mode-map "1" 'para-@)
  229.   (define-key para-mode-map "2" 'para-@)
  230.   (define-key para-mode-map "3" 'para-@)
  231.   (define-key para-mode-map "4" 'para-@)
  232.   (define-key para-mode-map "5" 'para-@)
  233.   (define-key para-mode-map "6" 'para-@)
  234.   (define-key para-mode-map "7" 'para-@)
  235.   (define-key para-mode-map "8" 'para-@)
  236.   (define-key para-mode-map "9" 'para-@)
  237.   (define-key para-mode-map "b" 'para-@)
  238.   (define-key para-mode-map "d" 'para-@)
  239.   (define-key para-mode-map "f" 'para-@)
  240.   (define-key para-mode-map "g" 'para-@)
  241.   (define-key para-mode-map "l" 'para-@)
  242.   (define-key para-mode-map "m" 'para-@)
  243.   (define-key para-mode-map "n" 'para-@)
  244.   (define-key para-mode-map "p" 'para-@)
  245.   (define-key para-mode-map "q" 'para-@)
  246.   (define-key para-mode-map "s" 'para-@)
  247.   (define-key para-mode-map "u" 'para-@)
  248.   (define-key para-mode-map "<" 'para-@)
  249.   (define-key para-mode-map ">" 'para-@)
  250.   (define-key para-mode-map "[" 'para-@)
  251.   (define-key para-mode-map "]" 'para-@)
  252.   (define-key para-mode-map "\C-?" 'para-@)
  253.  
  254. ;;; `C-c C-p' is the general prefix key for Para mode commands.
  255.  
  256. ;;; Go to first, second, third, etc. node in menu
  257.   (define-key para-mode-map "\C-c\C-p1" 'para-menu-1)
  258.   (define-key para-mode-map "\C-c\C-p2" 'para-menu-2)
  259.   (define-key para-mode-map "\C-c\C-p3" 'para-menu-3)
  260.   (define-key para-mode-map "\C-c\C-p4" 'para-menu-4)
  261.   (define-key para-mode-map "\C-c\C-p5" 'para-menu-5)
  262.   (define-key para-mode-map "\C-c\C-p6" 'para-menu-6)
  263.   (define-key para-mode-map "\C-c\C-p7" 'para-menu-7)
  264.   (define-key para-mode-map "\C-c\C-p8" 'para-menu-8)
  265.   (define-key para-mode-map "\C-c\C-p9" 'para-menu-9)
  266.   (define-key para-mode-map "\C-c\C-p0" 'para-menu-1x)
  267.  
  268. ;;; Para mode movement keybindings -- use only control characters:
  269.   (define-key para-mode-map "\C-c\C-p\C-b" 'para-beginning)
  270.   (define-key para-mode-map "\C-c\C-p\C-f" 'para-follow)
  271.   (define-key para-mode-map "\C-c\C-p\C-g" 'para-goto-node)
  272.   (define-key para-mode-map "\C-c\C-p\C-l" 'para-last)
  273.   (define-key para-mode-map "\C-c\C-p\C-m" 'para-menu)
  274.   (define-key para-mode-map "\C-c\C-p\C-n" 'para-next)
  275.   (define-key para-mode-map "\C-c\C-p\C-p" 'para-prev)
  276.   (define-key para-mode-map "\C-c\C-p\C-q" 'para-quit)
  277.   (define-key para-mode-map "\C-c\C-p\C-s" 'para-search)
  278.   (define-key para-mode-map "\C-c\C-p\C-u" 'para-up)
  279.   (define-key para-mode-map "\C-c\C-p\C-<" 'para-top-node)
  280.   (define-key para-mode-map "\C-c\C-p\C->" 'para-final)
  281.   (define-key para-mode-map "\C-c\C-p\C-]"
  282.     'para-goto-next-node-in-sequence)
  283.   (define-key para-mode-map "\C-c\C-p\C-["
  284.     'para-goto-previous-node-in-sequence)
  285.  
  286. ;;; Keybindings that create or change a buffer use prefix plus key.
  287.  
  288. ;;; Para mode keybindings for commands to create or change the Para
  289. ;;; mode file:
  290.  
  291.   (define-key para-mode-map "\C-c\C-pa" 'para-add-node)
  292.   (define-key para-mode-map "\C-c\C-pe" 'para-menu-explode)
  293.   (define-key para-mode-map "\C-c\C-pf" 'para-make-file)
  294.   (define-key para-mode-map "\C-c\C-pi" 'para-insert-menu)
  295.   (define-key para-mode-map "\C-c\C-pm" 'para-make-master-menu)
  296.   (define-key para-mode-map "\C-c\C-pr" 'para-xref)
  297.   (define-key para-mode-map "\C-c\C-pt" 'para-tagify)
  298.  
  299. ;;; Para mode keybindings for commands to create a temporary buffer
  300. ;;; listing all the nodes:
  301.  
  302.   (define-key para-mode-map "\C-c\C-pd" 'para-directory)
  303.   (define-key para-mode-map "\C-c\C-pl" 'para-list-visited-nodes)
  304.  
  305. ;;; Exception to C-c C-p keybinding conventions:
  306.   (define-key para-mode-map "\C-c\C-pn" 'para-narrow-to-node)
  307.  
  308. ;;; `C-c C-x' is the prefix key for Para indexing.
  309.  
  310.   (define-key para-mode-map "\C-c\C-xc" 'para-index-concept)
  311.   (define-key para-mode-map "\C-c\C-xf" 'para-index-function)
  312.   (define-key para-mode-map "\C-c\C-xk" 'para-index-keystroke)
  313.   (define-key para-mode-map "\C-c\C-xp" 'para-index-program)
  314.   (define-key para-mode-map "\C-c\C-xt" 'para-index-datatype)
  315.   (define-key para-mode-map "\C-c\C-xv" 'para-index-variable)
  316.  
  317.   (define-key para-mode-map "\C-c\C-xx" 'para-insert-index))
  318.  
  319. ;;; For bindings inside the temporary buffer created by
  320. ;;; `para-list-visited-nodes', use:
  321. ;;;
  322. ;;; C-c C-p r         para-visited-xref       (based on `para-xref')
  323. ;;; C-c C-p C-m       para-goto-visited-node  (parallel to `para-menu')
  324. ;;;
  325. ;;;  (Note that the keybinding for `para-visited-xref' and
  326. ;;;  `para-goto-visited-node' are defined locally in the mode map for
  327. ;;;  the temporary buffer, not in the para-mode-map.)
  328.  
  329. ;;; For bindings inside the temporary buffer created by
  330. ;;; `para-directory', use:
  331. ;;;
  332. ;;; C-c C-p r       para-main-menu-buffer-xref (based on `para-xref')
  333. ;;; C-c C-p C-m     para-main-menu-goto-node   (parallel to `para-menu')
  334. ;;;
  335. ;;; (Keybinding defined in local keymap.)
  336.  
  337.  
  338. ;;; Mode line for Para mode
  339.  
  340. (defvar para-ignore-extension nil
  341.   "*If non-nil, visited filename extension not shown in mode-line.")
  342.  
  343. (defun para-set-mode-line ()
  344.   (let ((filename (file-name-nondirectory (buffer-file-name))))
  345.     (if para-ignore-extension
  346.         (setq filename
  347.               (substring filename 0         ; name sans extension
  348.                          (or (string-match "\\.tex" filename)
  349.                              (length filename)))))
  350.     (setq mode-line-modified '("--%1*%1*-")
  351.       mode-line-buffer-identification
  352.       (concat "Para mode: ("
  353.                   filename
  354.                   ")"
  355.                   (or para-current-node "")
  356.                   " "))))
  357.  
  358.  
  359. ;;; Para mode
  360.  
  361. (defun para-mode ()
  362.   "Hypertext-like extension of Texinfo.
  363. Provides editing and Info-like movement commands for Texinfo files.
  364.  
  365. When point is at the upper-left corner, or if the buffer is read-only,
  366. Emacs interprets key strokes as Info-like commands.  Otherwise,
  367. keystrokes self-insert.
  368.  
  369. The default keybindings are compatible with
  370. Texinfo mode.  The prefix keys for the different groups of commands
  371. are:
  372.  
  373.       TeX commands              prefix key: `C-c C-t'
  374.       Elisp formatting commands prefix key: `C-c C-e'
  375.       Makeinfo commands         prefix key: `C-c C-m'
  376.       Updating commands         prefix key: `C-c C-u'
  377.       String insertion commands prefix key: `C-c C-c'
  378.  
  379.       Para indexing commands    prefix key: `C-c C-x'
  380.       Para mode general         prefix key: `C-c C-p'
  381.  
  382. Primary movement commands are similar to those in Info:
  383. \\<para-mode-map>
  384.     Display the first menu:             \\[para-directory]
  385.     Go to the `Next' node:              \\[para-next]
  386.     Go to the `Previous' node:          \\[para-prev]
  387.     Go to the `Up' node:                \\[para-up]
  388.     Go to the menu item named:          \\[para-menu]
  389.  
  390. Primary editing features are:
  391.  
  392.     Create a file in Para mode 
  393.         and insert its header:          \\[para-make-file]
  394.     Create a new node
  395.         and section header:             \\[para-add-node]
  396.     Insert a Texinfo menu template:     \\[para-insert-menu]
  397.     Create new node and section 
  398.         headers at the end of the 
  399.         current node, based on menu:    \\[para-menu-explode]
  400.     Insert Texinfo cross reference:     \\[para-xref]
  401.     Make a master menu:                 \\[para-make-master-menu]
  402.  
  403. The commands are:
  404.  
  405. \\{para-mode-map}"
  406.   (interactive)
  407.   (text-mode)
  408.   (kill-all-local-variables)
  409.   (use-local-map para-mode-map)
  410.   (set-syntax-table para-mode-syntax-table)
  411.   (setq mode-name "Para"
  412.         major-mode 'para-mode)
  413.   (make-variable-buffer-local 'para-main-menu-completions-list)
  414.   (make-local-variable 'require-final-newline)
  415.   (make-local-variable 'paragraph-separate)
  416.   (make-local-variable 'paragraph-start)
  417.   (make-local-variable 'fill-column)
  418.   (make-local-variable 'comment-start)
  419.   (make-local-variable 'comment-start-skip)
  420.   (make-local-variable 'para-history)
  421.   (make-local-variable 'para-current-node)
  422.   (make-local-variable 'para-ignore-extension)
  423.   (make-local-variable 'para-last-search)
  424.   (setq require-final-newline t
  425.         paragraph-separate (concat "^\b\\|^@[a-zA-Z]*[ \n]\\|"
  426.                                    paragraph-separate)
  427.         paragraph-start (concat "^\b\\|^@[a-zA-Z]*[ \n]\\|" paragraph-start)
  428.         fill-column 72
  429.         comment-start "@c \|@comment "
  430.         comment-start-skip "@c +\|@comment +")
  431.   (para-narrow-to-node)
  432.   (run-hooks 'text-mode-hook 'texinfo-mode-hook 'para-mode-hook))
  433.  
  434.  
  435. ;;; Make a Para mode file; or quit.
  436.  
  437. ;;;     C-c C-p f       para-make-file       Create a file in Para mode 
  438. ;;;     C-c C-p C-q     para-quit            Change to Texinfo mode
  439.  
  440. (defun para-make-file (filename title node-name chapter-name)
  441.   "Create a file in Para mode and insert its header.
  442. Filename should end in `.tex', `.texi', or `.texinfo'. extension.
  443.  
  444. This command inserts the `setfilename' and `settitle' commands used by
  445. Texinfo.  Prompts user for FILENAME, TITLE used by TeX, first
  446. NODE-NAME, and first CHAPTER-NAME.
  447.  
  448. The Info file name is generated from the FILENMAE by removing the
  449. extension and replacing it with `.info'.  If the file already exists
  450. an error is signaled."
  451.   
  452.   (interactive
  453.    (list
  454.     (read-from-minibuffer "File name: ")
  455.     (read-from-minibuffer "Title: ")
  456.     (read-from-minibuffer "Name for first node: ")
  457.     (read-from-minibuffer "Name for first chapter: ")))
  458.   
  459.   (if (file-exists-p filename)
  460.       (error "File `%s' already exists!" filename))
  461.   
  462.   (find-file filename)
  463.   (set-syntax-table para-mode-syntax-table)
  464.   (goto-char (point-min))
  465.   
  466.   (let ((info-filename
  467.          (concat
  468.           (file-name-nondirectory
  469.            (substring 
  470.             filename 
  471.             0                         
  472.             (or (string-match "\\.tex" filename) (length filename))))
  473.           ".info")))
  474.     
  475.     ;; Format:
  476.     
  477.     ;; \input texinfo    @c -*-para-*-
  478.     ;; @setfilename INFO-FILENAME
  479.     ;; @settitle TITLE
  480.     ;; 
  481.     ;; @node top, 
  482.     ;; 
  483.     ;; @node NODE-NAME
  484.     ;; @chapter CHAPTER-NAME
  485.     ;; ...
  486.     ;; @bye
  487.  
  488.     (insert "\\input texinfo    @c -*-para-*-\n")
  489.     (insert (format "@setfilename %s\n" info-filename))
  490.     (insert (format "@settitle %s\n\n"  title))
  491.     (insert "@node top, \n\n")
  492.     (insert (format "@node %s,\n" node-name))
  493.     (insert (format "@chapter %s\n\n\n\n" chapter-name))
  494.     (insert "@bye\n")
  495.     (para-mode)
  496.     (forward-line -3)
  497.     (widen)))
  498.  
  499. (defun para-quit ()
  500.   "Exit para mode"
  501.   (interactive)
  502.   (widen)
  503.   (texinfo-mode))
  504.  
  505.  
  506. ;;; Add a new node
  507. ;;;    C-c C-p a       para-add-node
  508.  
  509. (defun para-add-node (new-node-type name title)
  510.   "Create new node and section headers.
  511.  
  512. In interactive use, 
  513.  
  514.     1. No prefix argument: section type defaults to the same type as
  515.        the preceding node.
  516.  
  517.     2. With prefix arg, obtain a prompt for the section type.  A
  518.        default is offered, which one level lower than the preceding
  519.        node (unless the previous node is already at the lowest level).
  520.  
  521.     You are prompted for the node name and section title.
  522.  
  523. If the new node is 
  524.  
  525.     * at the same or lower hierarchical level than the preceding node,
  526.       the function inserts new headers at point;
  527.  
  528.     * at a higher hierarchical level than the preceding node,
  529.       the function inserts new headers just before next node of 
  530.       the new level, or at the end of the buffer.
  531.  
  532. The function updates the appropriate node lines and the associated
  533. menu, but not the main menu (unless the new node is a chapter).
  534.  
  535. In non-interactive use, the first argument is the TYPE or level of the
  536. new node; the second argument is the the node NAME and the and third
  537. argument is the section TITLE."
  538.   (interactive
  539.      (if (not current-prefix-arg) 
  540.          (let ((preceding-node-type (para-preceding-node-type)))
  541.            ;; top node case
  542.            (if (string= preceding-node-type "top")
  543.                (setq preceding-node-type "chapter"))
  544.            (list preceding-node-type
  545.                  (read-string
  546.                   (format "Node name for `%s' (end with RET): "
  547.                               (para-preceding-node-type)))
  548.                  (read-string "Title (end with RET): ")))
  549.        ;; Ask what new node level should be; this becomes the 
  550.        ;; value of new-node-type even though it starts out as
  551.        ;; the prefix arg
  552.        (list
  553.         (read-no-blanks-input
  554.          "New node level: "
  555.          (cdr (assoc (para-preceding-node-type) para-subtype-alist)))
  556.         (read-string "Node name (end with RET): ")
  557.         (read-string "Title (end with RET): "))))
  558.  
  559.   (let* ((preceding-node-type (para-preceding-node-type))
  560.          (new-node-general-type
  561.           (cdr (assoc preceding-node-type texinfo-section-to-generic-alist))))
  562.     ;; top node case
  563.     (if (string= preceding-node-type "top")
  564.         (setq preceding-node-type "chapter"
  565.               new-node-general-type "chapter"))
  566.  
  567.     ;; Adding new nodes has three cases:
  568.     ;;
  569.     ;;     1. New node is at same level as preceding node:
  570.     ;;        insert it at point.
  571.     ;;
  572.     ;;     2. New node is at lower level than preceding node:
  573.     ;;        also, insert it at point.
  574.     ;;
  575.     ;;     3. New node is at higher level than preceding node:
  576.     ;;        insert it at end of the preceding node of the same level
  577.     ;;        after any intervening nodes; i.e. put it just before the
  578.     ;;        next node of that level.
  579.  
  580.     (if (not new-node-type)
  581.         ;; 1. most common case; insert same level node at point
  582.         (insert
  583.          (format "\n@node %s,\n@%s %s\n" name preceding-node-type title))
  584.  
  585.       ;; Else insert a node at a different level:
  586.  
  587.       (setq new-node-general-type      
  588.             (cdr
  589.              (assoc
  590.               new-node-type texinfo-section-to-generic-alist)))
  591.  
  592.       ;; 2. If the node is at a same or lower level, insert at point;
  593.       ;; but if the node is at a higher level, insert it just before
  594.       ;; next node of that level.
  595.  
  596.       (if (node-same-or-lower-level-p new-node-type preceding-node-type)
  597.           (insert (format "\n@node %s,\n@%s %s\n" name new-node-type title))
  598.  
  599.         ;; 3. Else the new node level is higher then the preceding node.
  600.         ;; Find next node of that level:
  601.         (if (re-search-forward
  602.              (concat
  603.               "\\(^@node\\).*\n"        ; match node line
  604.               "\\(\\(^@c\\|^@if\\).*\n\\)?"    ; match comment or
  605.                                                ; ifinfo line, if any
  606.               (eval
  607.                (cdr                     ; return regexp for search
  608.                 (assoc
  609.                   new-node-general-type
  610.                  texinfo-update-menu-same-level-regexps))))
  611.              nil
  612.              'goto-end)
  613.             (goto-char (match-beginning 0))
  614.           (point-max))
  615.         (insert
  616.          (format "\n@node %s,\n@%s %s\n\n" name new-node-type title))
  617.         (forward-line -1)))
  618.  
  619.     ;; Finally, update relevant pointers and menu
  620.     (para-insert-update-pointers-&-menu new-node-general-type)
  621.     (message "Added new node: name, `%s'; title, `%s' ... Done."
  622.              name title)))
  623.  
  624.  
  625. ;;; Utility functions for `para-add-node'
  626.  
  627. (defun para-preceding-node-type ()
  628.   "Return type of preceding node as string, eg \"section\" or \"chapter\"."
  629.     (save-excursion
  630.       (end-of-line)
  631.       (if (re-search-backward "^@node" nil t)
  632.           (if (looking-at "^@node [ \t]*top")
  633.               ;; top node case: return top
  634.               "top"
  635.             ;;else
  636.             (if (re-search-forward
  637.                  (concat
  638.                   "\\(^@node\\).*\n"            ; match node line
  639.               "\\(\\(^@c\\|^@if\\).*\n\\)?"     ; match comment or
  640.                                                 ; ifinfo line, if any
  641.                   "\\(^@\\).*")                 ; match title line 
  642.                  nil 
  643.                  t)
  644.                 (buffer-substring
  645.                  (progn (beginning-of-line) ; copy its name
  646.                         (1+ (point)))
  647.                  (progn (forward-word 1)
  648.                         (point)))))
  649.         ;; else no node line found
  650.         (error "No preceding node!"))))
  651.  
  652. (defun node-same-or-lower-level-p (new-node-type preceding-node-type)
  653.   "t if NEW-NODE-TYPE at same or lower level as PRECEDING-NODE-TYPE."
  654.   (let ((new-node-general-type
  655.          (cdr (assoc new-node-type texinfo-section-to-generic-alist)))
  656.         (node-sequence
  657.          (assoc        ; returns list of same and lower types
  658.           (cdr (assoc         
  659.                 preceding-node-type
  660.                 texinfo-section-to-generic-alist))
  661.           para-matching-subtypes-alist)))
  662.     (node-in-sequence-p new-node-general-type node-sequence)))
  663.  
  664. (defun node-in-sequence-p (node node-sequence)
  665.   "Return t if NODE is at same or lower level in NODE-SEQUENCE.
  666. The node sequence is a list of strings of the general type of node,
  667. such as `subsection' or `unnumbered'."
  668.   (if node-sequence
  669.       (if (string= node
  670.                    (car node-sequence))
  671.           t
  672.         (node-in-sequence-p node (cdr node-sequence)))))
  673.  
  674.  
  675. ;;; `para-add-node' utility; goto node of specified general type
  676.  
  677. (defun para-goto-node-of-type (type direction)
  678.   "Move point to node of specified general TYPE in specified DIRECTION.
  679. Return nil if specified node not found, otherwise, move point."
  680.   (widen)
  681.   (let ((search-function
  682.          (cond ((eq direction 'next) 're-search-forward)
  683.                ((eq direction 'previous) 're-search-backward))))
  684.     (if (string= "chapter" type)
  685.         (if
  686.             (funcall search-function
  687.                      (concat
  688.                       "\\("
  689.                       "\\(^@node [ \t]*top\\)"    ; top node case
  690.                       "\\|"                       ; or
  691.                       "\\(^@node\\).*\n"          ; match node line
  692.                       "\\(\\(^@c\\|^@if\\).*\n\\)?"      ; match comment
  693.                                                   ; or ifinfo line, if any
  694.                       "\\(^@"                     ;match chapter line
  695.                       texinfo-chapter-level-regexp 
  696.                       "\\)"                 
  697.                       "\\)")
  698.                      nil
  699.                      t)
  700.             (goto-char (match-beginning 0))
  701.           ;; else node not found
  702.           nil)
  703.       ;;else not a chapter
  704.       (if (funcall search-function
  705.                    (concat
  706.                     "\\(^@node\\).*\n"     ; match node line
  707.                     "\\(\\(^@c\\|^@if\\).*\n\\)?" ; match comment 
  708.                                            ; or ifinfo line, if any
  709.                     (eval
  710.                      (cdr
  711.                       (assoc type texinfo-update-menu-same-level-regexps))))
  712.                    nil
  713.                    t)
  714.           (goto-char (match-beginning 0))
  715.         ;; else node not found
  716.         nil))))
  717.  
  718.  
  719. ;;; `para-add-node' utility; insert and update pointers and menu 
  720.  
  721. (defun para-insert-update-pointers-&-menu (new-node-general-type)
  722.   "Insert pointers of an added node, update other pointers and menu.
  723. Specifically, insert the Next, Previous, and Up pointers of the current
  724. node, update the pointers of the Next and Previous nodes, and update
  725. the menu for the added node."
  726.   (let ((auto-fill-hook nil))
  727.     (save-excursion
  728.     ;; First, update current node:
  729.     (if (not (re-search-backward "^@node" (point-min) t))
  730.         (error "Node line not found before this position."))
  731.     (texinfo-update-the-node)
  732.     ;; Second, update previous node:
  733.     (save-excursion
  734.       (if (para-goto-node-of-type new-node-general-type 'previous)
  735.           (texinfo-update-the-node)))
  736.     ;; Third, update next node:
  737.     (save-excursion
  738.       (if (para-goto-node-of-type new-node-general-type 'next)
  739.           (texinfo-update-the-node)))
  740.     ;; Finally, update the menu for this node
  741.     (save-excursion
  742.       (texinfo-make-one-menu new-node-general-type)))))
  743.  
  744.  
  745. ;;; Add new nodes based on menu:  `para-menu-explode'
  746.  
  747. (defun para-menu-explode ()
  748.   "Based on menu, create new node and section headers at end of current node.
  749. Each node name is extracted from a menu entry, and the corresponding
  750. section title is the same as the descriptive string in that menu
  751. entry."
  752.   (interactive)
  753.   (if (re-search-backward "^@node" (point-min) t)
  754.       (let* ((up-node (texinfo-copy-node-name))
  755.              (new-node-type
  756.               (cdr (assoc (para-preceding-node-type) para-subtype-alist)))
  757.              (new-node-general-type
  758.               (cdr (assoc new-node-type
  759.                           texinfo-section-to-generic-alist)))
  760.  
  761.              menu-end menu next-node previous-node)
  762.         
  763.         (if (string= new-node-general-type "subsubsection")
  764.             (error "This node is too deep to create subnodes."))
  765.         
  766.         (if (search-forward "\n@menu" nil t)
  767.             (save-excursion
  768.               (if (search-forward "\n@end menu" nil t)
  769.                   (setq menu-end (point))
  770.                 (error "No \"@end menu\" found!")))
  771.           (error "No menu found!"))
  772.         ;; create list of node names and titles
  773.         (while (not (looking-at "^@end menu"))
  774.           (setq menu
  775.                 (cons
  776.                  (cons
  777.                   (para-extract-menu-node-name)
  778.                   (para-main-menu-buffer-copy-description menu-end))
  779.                  menu))
  780.           (forward-line 1))
  781.         
  782.         (setq menu (reverse menu)
  783.               next-node (append (cdr menu) (list (cons "" "")))
  784.               previous-node (append (list (cons "" "")) menu))
  785.         
  786.         (if (re-search-forward "^@node\\|^@bye" (point-max) 'move)
  787.             (forward-line -1))
  788.         
  789.         (while menu
  790.           
  791.           (insert
  792.            (format
  793.             "\n@node %s, %s, %s, %s\n@%s %s\n"
  794.             (car (car menu)) (car (car next-node))
  795.             (car (car previous-node)) up-node
  796.             new-node-type (cdr (car menu))))
  797.           
  798.           (setq menu (cdr menu) 
  799.                 next-node (cdr next-node)
  800.                 previous-node (cdr previous-node)))
  801.         
  802.         (recenter -1))
  803.     (error "Node line not found before this position.")))
  804.  
  805.  
  806. ;;; Insert a Texinfo cross reference
  807. ;;; C-c C-p r       para-xref
  808.  
  809. (defun para-xref (insert-topic-p nodename description)
  810.   "Insert a Texinfo cross reference.
  811.  
  812. The first argument, if non-nil, means incorporate topic description in
  813. reference.  In interactive use, this argument is optional prefix
  814. argument.  The second argument is the NODENAME for the reference, the
  815. third argument is the topic DESCRIPTION.  
  816.  
  817. If `para-main-menu-completions-list' is non-nil, completion for node
  818. names in the list. \(No default offered---you have to type the
  819. beginning of the node name.  Type \\[para-directory] to generate a
  820. `para-main-menu-completions-list' if it does not exist.\)"
  821.   
  822.   (interactive
  823.    (let* ((completion-ignore-case t)
  824.           (insert-topic-p  current-prefix-arg)
  825.           (node-name
  826.            (if (get-buffer para-main-menu-buffer-name)
  827.                (save-excursion
  828.                  (set-buffer para-main-menu-buffer-name)
  829.                  (completing-read
  830.                   "Node name (with completion): "
  831.                   para-main-menu-completions-list))
  832.              (read-string "Node name: ")))
  833.  
  834.           (description
  835.            (if insert-topic-p  
  836.                (read-string "Topic description (end with RET): "
  837.                         (if (get-buffer para-main-menu-buffer-name)
  838.                             (save-excursion
  839.                               (set-buffer para-main-menu-buffer-name)
  840.                               (goto-char (point-min))
  841.                               (if (re-search-forward
  842.                                    (regexp-quote node-name)
  843.                                    nil t)
  844.                                   (progn
  845.                                     (beginning-of-line)
  846.                                     (search-forward ":")
  847.                                     (para-main-menu-buffer-copy-description
  848.                                      (point-max)))
  849.                                 ""))
  850.                           ""))
  851.              "")))
  852.      (list  insert-topic-p node-name description)))
  853.   (if (string= "" description)
  854.       (insert (format "@xref{%s}." nodename))
  855.     (insert (format "@xref{%s, , %s}." nodename  description))))
  856.  
  857.  
  858. ;;; Chapter, section, etc. types alists
  859. (defvar para-matching-subtypes-alist
  860.   '(("top" . ("chapter" "section" "subsection" "subsubsection"))
  861.  
  862.     ("chapter" . ("section" "subsection" "subsubsection"))
  863.     
  864.     ("section" . ("subsection" "subsubsection"))
  865.     
  866.     ("subsection" . ("subsubsection"))
  867.     
  868.     ("subsubsection" . nil))
  869.   "*Alist matchining each general section type with a list of its same
  870.   and sub types.")
  871.  
  872. (defvar para-subtype-alist
  873.   '(("top" . "chapter")
  874.  
  875.     ("chapter" . "section")
  876.     ("unnumbered" . "unnumberedsec")
  877.     ("majorheading" . "heading")
  878.     ("chapheading" . "heading")
  879.     ("appendix" . "appendixsec")
  880.     
  881.     ("section" . "subsection")
  882.     ("unnumberedsec" . "unnumberedsubsec")
  883.     ("heading" . "subheading")
  884.     ("appendixsec" . "appendixsubsec")
  885.     
  886.     ("subsection" . "subsubsection")
  887.     ("unnumberedsubsec" . "unnumberedsubsubsec")
  888.     ("subheading" . "subsubheading")
  889.     ("appendixsubsec" . "appendixsubsubsec")
  890.     
  891.     ("subsubsection" . "subsubsection")
  892.     ("unnumberedsubsubsec" . "unnumberedsubsubsec")
  893.     ("subsubheading" . "subsubheading")
  894.     ("appendixsubsubsec" . "appendixsubsubsec"))
  895.   "*Alist of section types and their subtypes.")
  896.  
  897.  
  898. ;;; Narrow to node
  899.  
  900. ;;;    C-c C-p n       para-narrow-to-node
  901.  
  902. (defun para-narrow-to-node ()
  903.   "Narrow to current node."
  904.   (interactive)
  905.   (let ((current-position (point))
  906.         end-of-node-name
  907.         beginning-of-node)
  908.     (widen)
  909.     (beginning-of-line)
  910.     (if (or (looking-at "^@node")
  911.             (re-search-backward "^@node"  nil 'move-to-limit))
  912.         ;; point is within a node
  913.         (progn
  914.           (re-search-forward "@node[ \t]*\\<\\([^,]*\\),")
  915.           (setq end-of-node-name
  916.                 (point)
  917.                 para-current-node
  918.                 (buffer-substring (match-beginning 1) (match-end 1)))
  919.           (beginning-of-line)
  920.           (while (looking-at "^@")
  921.             (forward-line -1))
  922.           (forward-line 1)
  923.           (setq beginning-of-node (point))
  924.           ;; skip past beginning node name
  925.           (goto-char end-of-node-name))
  926.       ;; else point is before first node
  927.       (setq beginning-of-node 1
  928.             para-current-node  "Beginning of Buffer"))
  929.     (para-set-mode-line)
  930.     ;; search for next node
  931.     (if (search-forward "\n@node" nil 'move-to-limit)
  932.         (progn
  933.           (beginning-of-line)
  934.           (while (looking-at "^@")
  935.             (forward-line -1))))
  936.     (narrow-to-region beginning-of-node (point))
  937.     (goto-char current-position)))
  938.  
  939.  
  940. ;;; Goto a node.
  941.  
  942. (defun para-goto-node (name)
  943.   "Go to NAME, which may be `nodename' or `(filename)nodename'.
  944. This is an interface to the function `para-goto'."
  945.   (interactive "sGoto: ")
  946.   (if (not (para-goto name)
  947.            (error "Node not found: %s " name))))
  948.  
  949. (defun para-goto (name)
  950.   "Go to NAME, which may be `nodename' or `(filename)nodename'.
  951. Use `para-goto-node' interactively."
  952.   
  953.   ;; If the string passed as `name' starts with a left parenthesis,
  954.   ;; then the text within parentheses is the name of a file
  955.   
  956.   (let (filename nodename)
  957.     (if (string-equal (substring name 0 1) (char-to-string ?\())
  958.         ;; then name starts with filename
  959.         (setq filename
  960.               (substring name 1 (string-match (char-to-string ?\)) name))
  961.               nodename
  962.               (substring name (1+ (string-match (char-to-string ?\))  name))))
  963.       ;; else name is nodename only
  964.       (setq filename nil
  965.             nodename name))
  966.     
  967.     (cond 
  968.            ;; if file name is `dir', go to Info directory
  969.            ((and filename
  970.                 (string= (downcase filename) "dir")) (Info-directory))
  971.  
  972.            (filename                       ; i.e., if there is a filename
  973.             (if (string-equal nodename "") ; go to file, which will
  974.                                            ; enter para mode if it is
  975.                                            ; that type
  976.                 (switch-to-buffer (find-file-noselect filename))
  977.               ;; else go to a  node in the file \(must be a Para mode file\)
  978.               (find-file filename)
  979.               (widen) 
  980.               (goto-char (point-min))
  981.               (para-goto nodename)))
  982.            
  983.            ((string-equal nodename "*")
  984.             (para-beginning)
  985.             (setq para-current-node nodename)
  986.             (setq para-history (cons para-current-node para-history))
  987.             (para-set-mode-line))
  988.           
  989.            ;; else must be a node to go to
  990.            (t
  991.             (let ((current-position (point)))
  992.               (widen)
  993.               (goto-char (point-max))
  994.               ;; if both a tag table and find node, goto it
  995.               (if (and
  996.                    (search-backward "End tag table\n@end ignore" nil t)
  997.                    (para-tag-table-find))
  998.                   ;; then
  999.                   (progn
  1000.                     (para-narrow-to-node)
  1001.                     ;; para-narrow-to-node specifies value of para-current-node
  1002.                     (setq para-history (cons para-current-node para-history))
  1003.                     (para-set-mode-line)
  1004.                     t)
  1005.                 ;; else either no tag table or node not in tag table
  1006.                 (if (re-search-backward
  1007.                      (concat "^@node [ \t]*" nodename) nil t)
  1008.                     ;; then
  1009.                     (progn
  1010.                       (para-narrow-to-node)
  1011.                       (setq para-history (cons para-current-node para-history))
  1012.                       (para-set-mode-line)
  1013.                       t)
  1014.                   ;; else could not find new node, return to current position
  1015.                   (goto-char current-position)
  1016.                   (para-narrow-to-node)
  1017.                   nil)))))))
  1018.  
  1019. (defun para-tag-table-find ()
  1020.   "Use a tag table to assist in going to a node quickly.
  1021. Tag table must be at the end of a Para mode file in an @ignore.
  1022. Point must be closer to the end than the beginning of the @ignore."
  1023.   (and (search-backward "@ignore\nTag table:" nil t)
  1024.        (search-forward (concat "Node: " nodename "\177") (point-max) t)
  1025.        (para-tag-search nodename (read (current-buffer)) 500)))
  1026.  
  1027. (defun para-tag-search (node point chunk)
  1028.   "Search for NODENAME from POINT, forward and back in CHUNK-sized spans."
  1029.   (let ((forward-search-position point)
  1030.     (backward-search-position point)
  1031.     (target-node (concat "^@node[ \t]+" (regexp-quote node) "[ \t]*,"))
  1032.         (max-limit (point-max))
  1033.     forward-limit backward-limit found)
  1034.     
  1035.     (while (not found)
  1036.       (setq forward-limit
  1037.             (min max-limit (+ forward-search-position chunk))
  1038.         backward-limit
  1039.             (max 1 (- backward-search-position chunk)))
  1040.       (goto-char forward-search-position)
  1041.       
  1042.       (if (and (< forward-search-position max-limit)
  1043.                (re-search-forward target-node forward-limit t))
  1044.           (progn
  1045.             (beginning-of-line)
  1046.             (setq found (point))) ; and exit while loop
  1047.         
  1048.     ;;else
  1049.         (goto-char backward-search-position)
  1050.     (if (and (< 1 backward-search-position)
  1051.                  (re-search-backward target-node backward-limit t))
  1052.             (setq found (point)) ; and exit while loop
  1053.           
  1054.           ;; else
  1055.       (if (and (= forward-search-position max-limit)
  1056.                    (= backward-search-position (point-min)))
  1057.           (setq found 'at-limits) ; and exit while loop
  1058.             ;; else repeat while loop 
  1059.         (setq forward-search-position forward-limit
  1060.                   backward-search-position backward-limit)))))
  1061.     
  1062.     (if (numberp found)
  1063.     (goto-char found)
  1064.       nil)))
  1065.  
  1066.  
  1067. ;;; Tagify a Para mode file
  1068.  
  1069. (defun para-tagify ()
  1070.   "Create or update a Para mode tag table in the current buffer."
  1071.   (interactive)
  1072.   ;; Save and restore point and restrictions.
  1073.   ;; `save-restriction' would not work
  1074.   ;; because it records the old max relative to the end.
  1075.   ;; Record it relative to the beginning.
  1076.   (let ((old-minimum (point-min))
  1077.     (old-maximum (point-max))
  1078.     (no-max (= (point-max) (1+ (buffer-size))))
  1079.     (old-point (point)))
  1080.     (unwind-protect
  1081.     (progn
  1082.       (widen)
  1083.       (goto-char 1)
  1084.       (let ((case-fold-search t)
  1085.         list)
  1086.         (while (search-forward "\n@node" nil t)
  1087.           (forward-line -1)
  1088.           (let ((beg (point)))
  1089.         (forward-line 2)
  1090.         (if (re-search-backward "^@node[ \t]+\\([^,]+\\)," beg t)
  1091.                     (setq list
  1092.               (cons (list (para-clean-name
  1093.                        (buffer-substring
  1094.                     (match-beginning 1)
  1095.                     (match-end 1))
  1096.                        " \t")
  1097.                       beg)
  1098.                 list)))))
  1099.         (goto-char (point-max))
  1100.         (let ((buffer-read-only nil))
  1101.           (if (not (search-backward "\n@bye" nil t))
  1102.                   (error "This file requires an `@bye'!")
  1103.                 ;; else removing existing tag table if there is one
  1104.                 (if (search-forward "\nEnd tag table\n@end ignore\n" nil t)
  1105.           (let ((end (point)))
  1106.             (search-backward "\nTag table:\n")
  1107.             (beginning-of-line)
  1108.             (delete-region (point) end))))
  1109.           (goto-char (point-max))
  1110.           (insert "\n \n@ignore\nTag table:\n")
  1111.           (setq list (nreverse list))
  1112.           (while list
  1113.         (insert "Node: " (car (car list)) ?\177)
  1114.         (princ (car (cdr (car list))) (current-buffer))
  1115.         (insert ?\n)
  1116.         (setq list (cdr list)))
  1117.         (insert "\nEnd tag table\n@end ignore\n")))))
  1118.       (goto-char old-point)
  1119.       (narrow-to-region old-minimum (if no-max (1+ (buffer-size))
  1120.                  (min old-maximum (point-max))))))
  1121.  
  1122. (defun para-clean-name (string chars-to-remove)
  1123.   "Remove leading/trailing characters from STRING that match CHARS-TO-REMOVE."
  1124.   (if (string= chars-to-remove "") string
  1125.     ;; else
  1126.     (let* ((i 0)
  1127.        (regex-to-remove (concat "[" chars-to-remove "]"))
  1128.        (dont-remove (concat "[^" chars-to-remove "]"))
  1129.            ;; delete leading chars-to-remove
  1130.        (string (substring string (or (string-match dont-remove string) 0)))
  1131.        (l (length string)))
  1132.       (while (and (< i l) (string-match regex-to-remove (substring string -1)))
  1133.     (setq i (1+ i) string (substring string 0 -1)))
  1134.       string)))
  1135.  
  1136.  
  1137. ;;; Insert a menu.
  1138. ;;;    C-c C-p i       para-insert-menu
  1139.  
  1140. (defun para-insert-menu () 
  1141.   "Insert a Texinfo menu template and position point within it."
  1142.   (interactive)
  1143.   (insert "@menu\n* ::\t\t\n@end menu\n")
  1144.   (forward-line -2)
  1145.   (forward-char 2))
  1146.  
  1147.  
  1148. ;;; Make a Master Menu
  1149.  
  1150. ;;; C-c C-p m       para-make-master-menu
  1151.  
  1152. ;;; `para-master-menu' is a rewrite of texinfo-master-menu and,
  1153. ;;; perhaps, should replace that function.  What is new is that
  1154. ;;; para-master-menu removes a pre-existing detailed part of the
  1155. ;;; master menu---but if the pre-existing master menu uses a
  1156. ;;; non-standard `texinfo-master-menu-header', this removal fails.
  1157. ;;; Also, para-master-menu removes extra blank lines that the menu
  1158. ;;; insert functions insert (and should insert, lest there be no blank
  1159. ;;; line separates when you make the first master menu).
  1160.  
  1161. ;;; Replace following with texinfo-master-menu?  Yes, but also provide
  1162. ;;; an indented master menu option.
  1163.  
  1164. ;;; Currently, `texinfo-master-menu' works like this:
  1165. ;;;  "Make a master menu for a whole Texinfo file.
  1166. ;;;Non-nil argument (prefix, if interactive) means first update all
  1167. ;;;existing nodes and menus.  Remove pre-existing master menu, if there is one.
  1168.  
  1169. (defun para-make-master-menu
  1170.   (&optional update-all-nodes-menus-p para-indented-master-menu-p)
  1171.   "Make a master menu for a whole Para mode file.
  1172.  
  1173. In interactive use:
  1174.  
  1175.     1. With no prefix arg, make a regular master menu, first removing
  1176.        detailed part of pre-existing master menu, if there is one.
  1177.  
  1178.     2. With prefix arg, first update all existing nodes and menus
  1179.        \(incorporating descriptions from pre-existing menus\), first
  1180.        removing detailed part of pre-existing master menu, if there is
  1181.        one.
  1182.  
  1183.     3. With numeric prefix arg, insert an indented master menu.  All
  1184.        the nodes are in sequence.
  1185.  
  1186.     4. With negative numeric prefix arg, first update all existing
  1187.        nodes and menus \(incorporating descriptions from pre-existing
  1188.        menus\).  First remove detailed part of pre-existing master
  1189.        menu, if there is one, then insert an indented master menu.
  1190.  
  1191. When called from a program, non-nil optional first arg means first
  1192. update all existing nodes and menus \(incorporating descriptions from
  1193. pre-existing menus\); non-nil optional second arg means insert an
  1194. indented master menu in which all the nodes are in sequence.
  1195.  
  1196. This function creates a menu that follows the top node.  It replaces
  1197. any existing menu there, first removing the detailed part of an
  1198. already existing master.  \(This action depends on the pre-exisitng
  1199. master menu using the standard `texinfo-master-menu-header'.\)
  1200.  
  1201. A regular master menu has the following format, which is adapted from the
  1202. recommendation in the Texinfo Manual:
  1203.  
  1204.    * The first part contains the major nodes in the Texinfo file: the
  1205.      nodes for the chapters, chapter-like sections, and the major
  1206.      appendices.  This includes the indices, so long as they are in
  1207.      chapter-like sections, such as unnumbered sections.
  1208.  
  1209.    * The second and subsequent parts contain a listing of the other,
  1210.      lower level menus, in order.  This way, an inquirer can go
  1211.      directly to a particular node if he or she is searching for
  1212.      specific information.
  1213.  
  1214. Each of the menus in the detailed node listing is introduced by the
  1215. title of the section containing the menu.
  1216.  
  1217. An indented master menu consists of all the menu entries in the
  1218. buffer, in sequence, with lower level menus indented according to
  1219. their hierarchical level."
  1220.   (interactive
  1221.    (cond ((not current-prefix-arg) (list nil nil))
  1222.          ((listp current-prefix-arg) (list t nil))
  1223.          ((> (prefix-numeric-value current-prefix-arg) 0) (list nil t))
  1224.          ((< (prefix-numeric-value current-prefix-arg) 0) (list t t))))
  1225.   (widen)
  1226.   (goto-char (point-min))
  1227.   
  1228.   ;; Move point to location after `top'.
  1229.   (if (not (re-search-forward "^@node [ \t]*top[ \t]*\\(,\\|$\\)" nil t))
  1230.       (error "This buffer needs a Top node!"))
  1231.   
  1232.   (let ((first-chapter                  
  1233.          (save-excursion (re-search-forward "^@node") (point))))
  1234.     (if (re-search-forward texinfo-master-menu-header first-chapter t)
  1235.         ;; Remove detailed master menu listing
  1236.         (progn
  1237.           (goto-char (match-beginning 0))
  1238.           (let ((end-of-detailed-menu-descriptions
  1239.                  (save-excursion     ; beginning of end menu line
  1240.                    (goto-char (texinfo-menu-end))
  1241.                    (beginning-of-line) (forward-char -1)
  1242.                    (point))))
  1243.             (delete-region (point) end-of-detailed-menu-descriptions)))))
  1244.   
  1245.   (if update-all-nodes-menus-p
  1246.       (progn
  1247.         (message "Making a master menu...first updating all nodes... ")
  1248.         (sleep-for 2)
  1249.         (mark-whole-buffer)
  1250.         (texinfo-update-node t)
  1251.         
  1252.         (message "Updating all menus... ")        
  1253.         (sleep-for 2)
  1254.         (mark-whole-buffer)
  1255.         (texinfo-make-menu t)))
  1256.   
  1257.   (message "Now making the master menu... ")
  1258.   (sleep-for 2)
  1259.   (goto-char (point-min))
  1260.   
  1261.   (if para-indented-master-menu-p
  1262.       (progn
  1263.         (para-insert-indented-master-menu)
  1264.         (message
  1265.          "Done...completed making indented master menu.  You may save the buffer."))
  1266.     ;; else
  1267.     (texinfo-insert-master-menu-list
  1268.      (texinfo-master-menu-list))
  1269.     
  1270.     ;; Remove extra newlines that texinfo-insert-master-menu-list
  1271.     ;; may have inserted.
  1272.     
  1273.     (save-excursion
  1274.       (goto-char (point-min))
  1275.       
  1276.       (re-search-forward texinfo-master-menu-header)
  1277.       (goto-char (match-beginning 0))
  1278.       (insert "\n")
  1279.       (delete-blank-lines)
  1280.       
  1281.       (re-search-backward "^@menu")
  1282.       (forward-line -1)
  1283.       (delete-blank-lines)
  1284.       
  1285.       (re-search-forward "^@end menu")
  1286.       (forward-line 1)
  1287.       (delete-blank-lines)
  1288.       
  1289.       (message 
  1290.        "Done...completed making master menu.  You may save the buffer."))))
  1291.  
  1292.  
  1293. ;;; Find node in current buffer or other file with `para-menu'.
  1294. ;;; C-c C-p C-m     para-menu
  1295.  
  1296. ; The format must be one of following:
  1297.  
  1298.     ; * nodename::                   description
  1299.     ; * item:nodename.               description
  1300.     ; * item:(filename).             description
  1301.     ; * item:(filename)nodename.     description
  1302.  
  1303. ; (The `description' is optional.)
  1304. ; The file name must either be to a file in the current directory or a
  1305. ; full, absolute pathname.
  1306. ; To go to the item, position the cursor at the beginning of the line
  1307. ; for the item and type `C-c C-p C-m' and then type a RET to confirm
  1308. ; the default item.
  1309.  
  1310. (defun para-menu (menu-item)
  1311.   "Go to node for menu item named (or abbreviated) NAME.
  1312. In interactive use, default is node under cursor. 
  1313. Completion for any name in this menu."
  1314.   (interactive
  1315.    (list
  1316.     (let (completions
  1317.       (p (point))
  1318.           (default
  1319.             (save-excursion
  1320.               (beginning-of-line)
  1321.               (if (re-search-forward "\\* \\([^:\t\n]*\\):" nil t)
  1322.                   (buffer-substring (match-beginning 1) (match-end 1))
  1323.                 (prog1 nil (message "No default menu item found."))))))
  1324.       (save-excursion
  1325.     (goto-char (point-min))
  1326.     (if (not (search-forward "\n@menu" nil t))
  1327.         (error "No menu in this node.")
  1328.           ;; create alist for completing-read
  1329.           (while (re-search-forward
  1330.                   "\\* \\([^:\t\n]*\\):" nil t)
  1331.             ;; make a list,
  1332.             ;; each of element of which is \("name" . position\)
  1333.             (setq completions (cons (cons (buffer-substring
  1334.                                            (match-beginning 1)
  1335.                                            (match-end 1))
  1336.                                           (match-beginning 1))
  1337.                                     completions)))
  1338.           (let (item)
  1339.             (setq item (let ((completion-ignore-case t))
  1340.                          (completing-read
  1341.                           (if default
  1342.                               (format "Menu item (default %s): " default)
  1343.                             "Menu item: ")
  1344.                           completions nil t)))
  1345.             (if (string= item "") default item)))))))
  1346.   (save-excursion
  1347.     (goto-char (point-min))
  1348.     (or (search-forward "\n@menu" nil t)
  1349.     (error "No menu in this node"))
  1350.     (para-goto (para-extract-menu-name menu-item))))
  1351.  
  1352. (defun para-extract-menu-name (menu-item)
  1353.   "Return `nodename' or `(filename)nodename' for MENU-ITEM.
  1354. Point must be on or before named menu-item."
  1355.   (beginning-of-line)
  1356.   (or (re-search-forward (concat "* " "\\(" menu-item "\\)") nil t)
  1357.       (error "No such item in menu"))
  1358.   (para-extract-menu-node-name))
  1359.  
  1360. (defun para-extract-menu-node-name ()
  1361.   "Return `nodename' or `(filename)nodename'
  1362. Point must be on or before menu line."
  1363.  
  1364. ;;; Four circumstances:
  1365.  
  1366. ;;; * nodename::                   description
  1367. ;;; * item:nodename.               description
  1368. ;;; * item:(filename).             description
  1369. ;;; * item:(filename)nodename.     description
  1370.  
  1371. ;;; If a nodename is the second part of a menu item, you may follow it
  1372. ;;; with a period, comma, tab, or newline.
  1373.  
  1374.   (beginning-of-line)
  1375.   (or (re-search-forward (concat "* \\(\\w+\\)") nil t)
  1376.       (error "Cannot find a menu line."))
  1377.   (let ((start-of-name (match-beginning 1))
  1378.         node)
  1379.     (if (and
  1380.          (search-forward ":" nil t)
  1381.          (looking-at ":"))                            ; look at `::'
  1382.         (setq node
  1383.               (buffer-substring start-of-name (1- (point)))) ; return nodename
  1384.       ;;else
  1385.       (skip-chars-forward ": \t")
  1386.       (setq start-of-name (point))
  1387.       (if (search-forward "(" nil t)    ; skip over node name, if any
  1388.           (progn (goto-char (1- (point)))
  1389.                  (forward-sexp)))
  1390.       (re-search-forward "[.,\t\n]" nil t)
  1391.       ;; return either `nodename',`(filename)', or `(filename)nodename'
  1392.       (setq node (buffer-substring start-of-name (1- (point)))))
  1393.     node))
  1394.  
  1395.  
  1396. ;;; Goto the first, second, third node in a menu.
  1397. ;;;    C-c C-p 1       para-menu-1      go to the node of the first menu 
  1398. ;;;                                        item, etc., up to `9'
  1399.  
  1400. ;;; Go to first, second, third etc. menu item
  1401.  
  1402. (defun para-menu-1 ()
  1403.   "Go to the node of the first menu item."
  1404.   (interactive)
  1405.   (if (not (para-goto (para-menu-count 1)))
  1406.       (error "Node not found.")))
  1407.  
  1408. (defun para-menu-2 ()
  1409.   "Go to the node of the second menu item."
  1410.   (interactive)
  1411.   (if (not (para-goto (para-menu-count 2)))
  1412.       (error "Node not found.")))
  1413.  
  1414. (defun para-menu-3 ()
  1415.   "Go to the node of the third menu item."
  1416.   (interactive)
  1417.   (if (not (para-goto (para-menu-count 3)))
  1418.       (error "Node not found.")))
  1419.  
  1420. (defun para-menu-4 ()
  1421.   "Go to the node of the fourth menu item."
  1422.   (interactive)
  1423.   (if (not (para-goto (para-menu-count 4)))
  1424.       (error "Node not found.")))
  1425.  
  1426. (defun para-menu-5 ()
  1427.   "Go to the node of the fifth menu item."
  1428.   (interactive)
  1429.   (if (not (para-goto (para-menu-count 5)))
  1430.       (error "Node not found.")))
  1431.  
  1432. (defun para-menu-6 ()
  1433.   "Go to the node of the sixth menu item."
  1434.   (interactive)
  1435.   (if (not (para-goto (para-menu-count 6)))
  1436.       (error "Node not found.")))
  1437.  
  1438. (defun para-menu-7 ()
  1439.   "Go to the node of the seventh menu item."
  1440.   (interactive)
  1441.   (if (not (para-goto (para-menu-count 7)))
  1442.       (error "Node not found.")))
  1443.  
  1444. (defun para-menu-8 ()
  1445.   "Go to the node of the eighth menu item."
  1446.   (interactive)
  1447.   (if (not (para-goto (para-menu-count 8)))
  1448.       (error "Node not found.")))
  1449.  
  1450. (defun para-menu-9 ()
  1451.   "Go to the node of the ninth menu item."
  1452.   (interactive)
  1453.   (if (not (para-goto (para-menu-count 9)))
  1454.       (error "Node not found.")))
  1455.  
  1456. (defun para-menu-1x (count)
  1457.   "Go to the prompted for menu item number."
  1458.   (interactive "nMenu item #: ")
  1459.   (if (not (para-goto (para-menu-count count)))
  1460.       (error "Node not found.")))
  1461.  
  1462. (defun para-menu-count (count)
  1463.   (let (name)
  1464.     (save-excursion
  1465.       (goto-char (point-min))
  1466.       (or (search-forward "\n@menu" nil t)
  1467.           (error "No menu in this node"))
  1468.       (or  (re-search-forward "\n[ ]*\\* \\([^:\t\n]*\\):" nil t count)
  1469.            (error "Too few items in menu"))
  1470.       (beginning-of-line)
  1471.       (if (setq name (para-extract-menu-name 
  1472.                       (buffer-substring (match-beginning 1) (match-end 1))))
  1473.           name
  1474.         (error "Node not found.")))))
  1475.  
  1476.  
  1477. ;;; Display the first menu in a temporary buffer using `para-directory'
  1478. ;;; C-c C-p d     para-directory
  1479.  
  1480.  
  1481. (defvar para-main-menu-buffer-name ""
  1482.   "Temporary buffer used by `para-directory' for main menu.
  1483. Also, used by `para-xref' and `para-visited-xref' for cross reference
  1484. completion.")
  1485.  
  1486. (defun para-directory ()
  1487.   "Display the first menu in a temporary buffer.
  1488. Usually, the first menu is the master menu.
  1489.  
  1490. In this buffer,
  1491. \\<para-main-menu-buffer-mode-map>
  1492.  
  1493. `para-main-menu-goto-node' is bound to \\[para-main-menu-goto-node]
  1494.  
  1495. which will jump you to the prompted for node in the Para Mode file.
  1496. Default is the name of the node under the cursor.  Completion offered.
  1497.  
  1498. Also,
  1499.  
  1500. `para-main-menu-buffer-xref'  is bound to \\[para-main-menu-buffer-xref]
  1501.  
  1502. which inserts a Texinfo cross reference in the associated Para mode
  1503. file at the current position of point in the Para mode file.  Default
  1504. is the name of the node under the cursor.  With optional argument
  1505. \(prefix if interactive\), Emacs prompts you for a topic description.
  1506. Completion is offered, but only for node names listed in this
  1507. temporary buffer."
  1508.   
  1509.   (interactive)
  1510.   (setq para-current-buffer (current-buffer))
  1511.   (setq para-main-menu-buffer-name
  1512.         (concat para-main-menu-prefix (buffer-name) " "))
  1513.   (let (this-node
  1514.         (this-line 0))
  1515.     (save-excursion
  1516.       (save-restriction
  1517.         (widen)
  1518.         ;; Record current node name for later positioning in buffer.
  1519.         (end-of-line)
  1520.         (if (re-search-backward "^@node" nil t)
  1521.             (setq this-node (texinfo-copy-node-name))
  1522.           (setq this-node nil))
  1523.         (goto-char (point-min))
  1524.         (if (not (re-search-forward "^@menu"))
  1525.             (error "Menu not found!"))
  1526.         (forward-line 1)
  1527.         (let ((menu
  1528.                (buffer-substring
  1529.                 (point)
  1530.                 (save-excursion 
  1531.                   (if (not (re-search-forward "^@end menu" nil t))
  1532.                       (error "End of menu not found!"))
  1533.                   (beginning-of-line)
  1534.                   (point)))))
  1535.           
  1536.           (with-output-to-temp-buffer para-main-menu-buffer-name
  1537.             (set-buffer para-main-menu-buffer-name)
  1538.             (kill-all-local-variables)
  1539.             (set-syntax-table para-mode-syntax-table)
  1540.             (use-local-map para-main-menu-buffer-mode-map)
  1541.             
  1542.             (setq mode-name "Para Menu"
  1543.                   major-mode 'para-main-menu-buffer-mode)
  1544.             (insert menu)
  1545.             (setq buffer-read-only t)
  1546.             ;; create alist for completing-read
  1547.             (goto-char (point-min))
  1548.             (while (re-search-forward
  1549.                     "\n[ ]*\\* \\([^:\t\n]*\\):" nil t)
  1550.               ;; make a list,
  1551.               ;; each of element of which is \("name" . position\)
  1552.               (setq para-main-menu-completions-list
  1553.                     (cons (cons (buffer-substring
  1554.                                  (match-beginning 1)
  1555.                                  (match-end 1))
  1556.                                 (match-beginning 1))
  1557.                           para-main-menu-completions-list)))
  1558.             (goto-char (point-min))
  1559.             ))))
  1560.     (pop-to-buffer para-main-menu-buffer-name)
  1561.     (and this-node
  1562.          (re-search-forward this-node nil t) (beginning-of-line))))
  1563.  
  1564.  
  1565. ;;; Utility functions for displaying first menu
  1566.  
  1567. ;;; Includes commands to go to the node under the cursor and to insert
  1568. ;;; a cross reference in the source file refering to the node under
  1569. ;;; the cursor
  1570.  
  1571. (defvar para-main-menu-prefix "*Menu for: "
  1572.   "Prefix of name of temporary buffer displaying the main menu.")
  1573.  
  1574. (defvar para-main-menu-buffer-mode-map nil
  1575.   "Keymap used in temporary buffer displaying the main menu.")
  1576.  
  1577. ;;; !!! remove this setq after testing
  1578. (setq para-main-menu-buffer-mode-map nil)
  1579.  
  1580. (if para-main-menu-buffer-mode-map
  1581.     nil
  1582.   (setq para-main-menu-buffer-mode-map (copy-keymap text-mode-map))
  1583.   (define-key para-main-menu-buffer-mode-map "n"     'next-line)
  1584.   (define-key para-main-menu-buffer-mode-map " "     'next-line)
  1585.   (define-key para-main-menu-buffer-mode-map "p"     'previous-line)
  1586.   (define-key para-main-menu-buffer-mode-map "\177"  'previous-line)
  1587.   (define-key para-main-menu-buffer-mode-map "q"     
  1588.     '(lambda () "Bury current buffer; switch to current Para mode buffer."
  1589.        (interactive)
  1590.        (bury-buffer (current-buffer))
  1591.        (switch-to-buffer para-current-buffer)))
  1592.   (define-key para-main-menu-buffer-mode-map "\C-c\C-p\C-m"
  1593.     'para-main-menu-goto-node)
  1594.   (define-key para-main-menu-buffer-mode-map "m" 
  1595.     'para-main-menu-goto-node)
  1596.   (define-key para-main-menu-buffer-mode-map "\C-c\C-pr"
  1597.     'para-main-menu-buffer-xref)
  1598.   (define-key para-main-menu-buffer-mode-map "r"
  1599.     'para-main-menu-buffer-xref))
  1600.  
  1601. (defvar para-main-menu-completions-list nil
  1602. "List used by `para-main-menu-goto-node' for completions.")
  1603.  
  1604.  
  1605. ;;; Menu goto function for `para-directory'
  1606.  
  1607. ;;; !!! check whether this handles menus of form:
  1608. ;;;     * item:(filename)nodename.     description
  1609.  
  1610. (defun para-main-menu-goto-node (menu-item)
  1611.   "Go to the Para mode node prompted for; default is node under cursor.
  1612. Completion."
  1613.   (interactive
  1614.    (list
  1615.     (let ((default
  1616.             (save-excursion
  1617.               (beginning-of-line)
  1618.               (re-search-forward "\\* \\([^:\t\n]*\\):" nil t)
  1619.               (buffer-substring (match-beginning 1) (match-end 1))))
  1620.           item)
  1621.       (setq item (let ((completion-ignore-case t))
  1622.                    (completing-read (if default
  1623.                         (format "Node name (default %s): " default)
  1624.                       "Node name: ")
  1625.                     para-main-menu-completions-list nil t)))
  1626.       (if (string= item "") default item))))
  1627.   (let ((file-name (para-extract-menu-file-name))
  1628.         (node-name (para-extract-menu-name menu-item)))
  1629.     (pop-to-buffer (get-file-buffer file-name))
  1630.     (if (not (para-goto node-name))
  1631.         (error "Node not found: %s " node-name))))
  1632.  
  1633. (defun para-extract-menu-file-name ()
  1634.   "Return name of Para mode file for which this is the menu buffer."
  1635.   (let ((menu-file  (buffer-name)))
  1636.     (substring menu-file
  1637.              (progn (string-match para-main-menu-prefix menu-file)
  1638.                     (match-end 0)) -1)))
  1639.  
  1640.  
  1641. ;;; `para-directory'  cross reference insertion
  1642.  
  1643. (defun para-main-menu-buffer-xref
  1644.   (reference &optional topic-description)
  1645.   "Insert cross reference in Texinfo file to name of node under cursor.
  1646.  
  1647. The function inserts a Texinfo cross reference in the associated Para
  1648. mode file at the current position of point in the Para mode file.
  1649. Default is the name of the node under the cursor.  Completion.
  1650.  
  1651. Optional second arg is topic description; with prefix arg if
  1652. interactive, prompt for topic description."
  1653.   
  1654.   (interactive
  1655.     (let ((default
  1656.             (save-excursion
  1657.              (para-extract-menu-name 
  1658.               (progn
  1659.                (beginning-of-line)
  1660.                (re-search-forward "\\* \\([^:\t\n]*\\):" nil t)
  1661.                (buffer-substring (match-beginning 1) (match-end 1))))))
  1662.           (description "")
  1663.           node-name)
  1664.       (setq node-name 
  1665.             (let ((completion-ignore-case t))
  1666.               (completing-read
  1667.                (if default
  1668.                    (format "Node name (default %s): " default)
  1669.                  "Node name: ")
  1670.                para-main-menu-completions-list nil t)))
  1671.       (if (string= node-name "") (setq node-name default))
  1672.       (if current-prefix-arg
  1673.           (setq description
  1674.                 (read-string
  1675.                  "Topic description (end with RET): " 
  1676.                  (save-excursion
  1677.                    (goto-char (point-min))
  1678.                    (if (search-forward node-name nil t)
  1679.                        (para-main-menu-buffer-copy-description
  1680.                         (point-max)))))))
  1681.       (list node-name description)))
  1682.   (pop-to-buffer (get-file-buffer (para-extract-menu-file-name)))
  1683.   (if (string= "" topic-description)
  1684.       (insert (format "@xref{%s}." reference))
  1685.     (insert (format "@xref{%s, , %s}." reference topic-description))))
  1686.  
  1687. ;;; merge with texinfo-menu-copy-old-description 
  1688. ;;; this function handles the texinfo-master-menu-header
  1689. (defun para-main-menu-buffer-copy-description (end-of-menu)
  1690.  
  1691.   "Return description field of menu line as a string.
  1692. Point must be located on the same line before the description.  Point
  1693. left before description.  Single argument, END-OF-MENU, is position
  1694. limiting search."
  1695.   (skip-chars-forward "[:.,\t\n ]+")
  1696. ;  (re-search-forward ":[^:.,\t\n]*[:.,\t\n]+")
  1697.   ;; don't copy a carriage return at line beginning with asterisk!
  1698.   (if (and (looking-at "\\w+")    
  1699.            (not (looking-at
  1700.                  (concat 
  1701.                   "\\("
  1702.                   "^[ \t]\\* "          ; beginning of menu line
  1703.                   "\\|"
  1704.                   "^@end menu"          ; end of menu
  1705.                   "\\|"
  1706.                   texinfo-master-menu-header ; header line
  1707.                   "\\)"))))
  1708.       (buffer-substring
  1709.        (point)
  1710.        (save-excursion
  1711.          (if (not (if (re-search-forward 
  1712.                        (concat 
  1713.                         "\\("                ; beginning of menu line
  1714.                         "^[ \t]*\\* "        ; works with master directory
  1715.                         "\\|"
  1716.                         "^@end menu"         ; end of menu
  1717.                         "\\|"                ; text at beginning of line
  1718.                         "^\\w+"              ;  is usually not part of desc.
  1719.                         "\\|"
  1720.                         texinfo-master-menu-header ; header line
  1721.                         "\\)")
  1722.                        end-of-menu t)
  1723.                       (goto-char (match-beginning 1))))
  1724.              (goto-char end-of-menu))
  1725.          (forward-line -1)
  1726.          (while (looking-at "[ \t]*$")
  1727.            (forward-line -1))
  1728.          (end-of-line)                  ; go to end of last description line
  1729.          (point)))
  1730.     ""))
  1731.  
  1732.  
  1733. ;;; Utility functions to create indented menus
  1734.  
  1735. ;;; used by `para-make-master-menu'
  1736.  
  1737. (defun para-insert-indented-master-menu ()
  1738.   "Insert an indented master menu in the current buffer."
  1739.   (re-search-forward "^@menu")
  1740.   (beginning-of-line)
  1741.   (let* ((buffer-original-position (point))
  1742.          (master-menu (para-list-directory-list-menus-indentedly)))
  1743.     (goto-char buffer-original-position)
  1744.     ;; Delete existing menu; buffer must have ordinary top menu
  1745.     (delete-region (point)  
  1746.                    (save-excursion (re-search-forward "^@end menu") (point)))
  1747.     ;; Handle top of menu
  1748.     (insert "@menu\n")
  1749.     (while  (car master-menu)
  1750.       (insert (format "%s" (car master-menu)))
  1751.       (setq master-menu (cdr master-menu)))
  1752.     ;; Finish menu
  1753.     (insert "@end menu")))
  1754.  
  1755. (defun para-list-directory-list-menus-indentedly ()
  1756.   "List node names and descriptions as indented menu entries.
  1757. Must start after first menu.  Returns list of menu entries."
  1758.   (let ((master-directory-list))
  1759.     (while (re-search-forward "^@node" nil t)
  1760.       (beginning-of-line)
  1761.  
  1762.       (let ((spaces (para-list-directory-indent-spaces))
  1763.             (this-node (texinfo-copy-node-name)))
  1764.         (message "Getting menu entry for `%s' ... " this-node)
  1765.         (save-excursion
  1766.           (if (re-search-backward (concat "\\* " this-node ":") nil t)
  1767.               (setq master-directory-list
  1768.                     (cons
  1769.                      (concat
  1770.                       (para-list-directory-indent-spaces)
  1771.                       (para-list-directory-menu-entry))
  1772.                      master-directory-list))
  1773.             ;; else no menu entry
  1774.             )))
  1775.       (end-of-line))
  1776.     (nreverse master-directory-list)))
  1777.  
  1778. (defun para-list-directory-indent-spaces ()
  1779.   "Return a string of spaces according to level of menu."
  1780.   (cdr (assoc
  1781.         (texinfo-hierarchic-level)
  1782.        ;; Perhaps this alist should be a variable rather than written in.
  1783.        '(("chapter" . "")
  1784.          ("section" . "  ")
  1785.          ("subsection" . "    ")
  1786.          ("subsubsection" . "      ")))))
  1787.  
  1788. (defun para-list-directory-menu-entry ()
  1789.   "Return this menu entry, including description, as string.
  1790. Start at beginning of line."
  1791.   (buffer-substring (point)
  1792.                     (save-excursion
  1793.                       (end-of-line)
  1794.                       (re-search-forward
  1795.                        (concat
  1796.                         "\\(\\* \\([^:\t\n]*\\):"
  1797.                         "\\|^@end menu"
  1798.                         "\\|"
  1799.                         texinfo-master-menu-header
  1800.                         "\\)")
  1801.                         nil
  1802.                         t)
  1803.                       (goto-char (match-beginning 0))
  1804.                       (beginning-of-line)
  1805.                       (point))))
  1806.  
  1807.  
  1808. ;;; Display recently visited nodes in a temporary buffer
  1809.  
  1810. ;;; History of visited nodes; easy cross reference making
  1811.  
  1812. ;;; `para-list-visited-nodes' displays a list of the nodes you have
  1813. ;;; visited in the Para mode file, most recent first.  The nodes are
  1814. ;;; displayed in a temporary buffer.
  1815. ;;;
  1816. ;;; `para-goto-visited-node' jumps you to the prompted for node in the
  1817. ;;; Para Mode file.  Default is the name of the node under the cursor.
  1818. ;;; Completion."
  1819. ;;;
  1820. ;;; `para-visited-xref' inserts a cross reference in the current Para
  1821. ;;; mode buffer at point in that buffer. The default node name is the
  1822. ;;; name of the node under the cursor in the `*Recently Visited
  1823. ;;; Nodes*' buffer.  Completion offered for other node names, but only
  1824. ;;; for node names listed in the `*Recently Visited Nodes*' buffer
  1825. ;;; This function makes it easier to insert cross references,
  1826. ;;; expecially when you cannot readily remember the node names.
  1827. ;;;
  1828. ;;; With optional argument (prefix if interactive), Emacs prompts you
  1829. ;;; for a topic description.
  1830.  
  1831. ;;; Keybindings are:
  1832. ;;;
  1833. ;;; C-c C-p l       para-list-visited-nodes
  1834. ;;;
  1835. ;;; For bindings inside the temporary buffer created by
  1836. ;;; `para-list-visited-nodes', use
  1837. ;;;
  1838. ;;; C-c C-p r       para-visited-xref       (based on `para-xref')
  1839. ;;; C-c C-p C-m     para-goto-visited-node  (parallel to `para-menu')
  1840. ;;;
  1841. ;;;  (Note that the keybinding for `para-visited-xref' and
  1842. ;;;  `para-goto-visited-node' are defined locally in the temporary
  1843. ;;;  buffer, not in the para-mode-map.)
  1844.  
  1845. (defvar para-history nil
  1846.   "List of names of recently visited nodes.")
  1847.  
  1848. (defvar para-current-buffer nil
  1849.   "Current buffer in Para Mode.")
  1850.  
  1851. (defvar para-current-node nil
  1852.   "Current Para Mode node.")
  1853.  
  1854. (defvar para-list-visited-nodes-syntax-table nil)
  1855.  
  1856. (if para-list-visited-nodes-syntax-table nil
  1857.   (setq para-mode-syntax-table (make-syntax-table))
  1858.       (modify-syntax-entry ?\" "\"" para-list-visited-nodes-syntax-table))
  1859.  
  1860. (defvar para-list-visited-nodes-mode-map nil 
  1861. "Keymap used in node listing buffer in Para mode.")
  1862.  
  1863. ;;; !!! remove this setq after testing
  1864. (setq para-list-visited-nodes-mode-map nil)
  1865.  
  1866. (if para-list-visited-nodes-mode-map
  1867.     nil
  1868.   (setq para-list-visited-nodes-mode-map (copy-keymap text-mode-map))
  1869.   (define-key para-list-visited-nodes-mode-map "n"     'next-line)
  1870.   (define-key para-list-visited-nodes-mode-map " "     'next-line)
  1871.   (define-key para-list-visited-nodes-mode-map "p"     'previous-line)
  1872.   (define-key para-list-visited-nodes-mode-map "\177"  'previous-line)
  1873.   (define-key para-list-visited-nodes-mode-map "q"     
  1874.     '(lambda () "Bury current buffer; switch to current Para mode buffer."
  1875.        (interactive)
  1876.        (bury-buffer (current-buffer))
  1877.        (switch-to-buffer para-current-buffer)))
  1878.   (define-key para-list-visited-nodes-mode-map "\C-c\C-p\C-m"
  1879.     'para-goto-visited-node)
  1880.   (define-key para-list-visited-nodes-mode-map "m" 
  1881.     'para-goto-visited-node)
  1882.   (define-key para-list-visited-nodes-mode-map "\C-c\C-pr"
  1883.     'para-visited-xref)
  1884.   (define-key para-list-visited-nodes-mode-map "r"
  1885.     'para-visited-xref))
  1886.  
  1887.  
  1888. ;;; List recently visited nodes.
  1889. ;;; C-c C-p l       para-list-visited-nodes
  1890.  
  1891. (defun para-list-visited-nodes ()
  1892.   "Display a list of recently visited nodes in a temporary buffer.
  1893.  
  1894. In this buffer,
  1895. \\<para-list-visited-nodes-mode-map>
  1896.  
  1897. `para-visited-xref' is bound to \\[para-visited-xref]
  1898.  
  1899. which inserts a Texinfo cross reference in the associated Para mode
  1900. file at the current position of point in the Para mode file.  Default
  1901. is the name of the node under the cursor.  Completion is offered, but
  1902. only for node names listed in this temporary buffer.
  1903.  
  1904. With optional argument (prefix if interactive), Emacs prompts you
  1905. for a topic description.
  1906.  
  1907. `para-goto-visited-node' is bound to \\[para-goto-visited-node] 
  1908.  
  1909. which will jump you to the prompted for node in the Para Mode file.
  1910. Default is the name of the node under the cursor.  Completion offered."
  1911.  
  1912.   (interactive)
  1913.   (setq para-current-buffer (current-buffer))
  1914.  
  1915. ;;; para-history is set in para-last and para-goto
  1916.  
  1917.   (let ((visited-list para-history))
  1918.     (with-output-to-temp-buffer "*Recently Visited Nodes*"
  1919.       (pop-to-buffer "*Recently Visited Nodes*")
  1920.       (kill-all-local-variables)
  1921.       (use-local-map para-list-visited-nodes-mode-map)
  1922.       (setq mode-name ""
  1923.             major-mode 'para-list-visited-nodes-mode)
  1924.       (set-syntax-table para-mode-syntax-table)
  1925.       (while (car visited-list)
  1926.         (insert (format "\"%s\"\n"  (car visited-list)))
  1927.         (setq visited-list (cdr visited-list))))))
  1928.  
  1929. (defun para-goto-visited-node (node-name)
  1930.   "Go to the Para mode node prompted for; default is node under cursor.
  1931. Completion."
  1932. ;;; Format of recently visited nodes buffer is the following:
  1933. ;;; 
  1934. ;;; "Create Files and Nodes"
  1935. ;;; "Movement Commands"
  1936. ;;; "Shortcut Commands"
  1937. ;;; "Para Mode Commands"
  1938.   
  1939.   (interactive
  1940.    (let ((default 
  1941.            (save-excursion
  1942.              (beginning-of-line)
  1943.              (re-search-forward "^\"\\([^\"]+\\)\"$" nil t)
  1944.              (buffer-substring (match-beginning 1) (match-end 1))))
  1945.          (description "")
  1946.          completions)
  1947.      (save-excursion              ; create alist for completing-read
  1948.        (goto-char (point-min))
  1949.        (while (re-search-forward "^\"\\([^\"]+\\)\"$" nil t)
  1950.          ;; make a list each of element of which is \("name" . position\)
  1951.          (setq completions (cons (cons (buffer-substring
  1952.                                         (match-beginning 1)
  1953.                                         (match-end 1))
  1954.                                        (match-beginning 1))
  1955.                                  completions))))
  1956.      (setq node-name
  1957.            (let ((completion-ignore-case t))
  1958.              (completing-read
  1959.               (if default
  1960.                   (format "Node name (default %s): " default)
  1961.                 "Node name: ")
  1962.               completions nil t)))
  1963.      (if (string= node-name "") (setq node-name default))
  1964.      (list node-name)))
  1965.   (pop-to-buffer para-current-buffer)
  1966.   (if (not (para-goto node-name))
  1967.       (error "Node not found: %s " node-name)))
  1968.  
  1969. (defun para-visited-xref   (reference &optional topic-description)
  1970.   "Insert cross reference to node cursor is on in Texinfo file.
  1971.  
  1972. The function inserts a Texinfo cross reference in the associated Para
  1973. mode file at the current position of point in the Para mode file.
  1974. Default is the name of the node under the cursor.  Completion for
  1975. other node names listed in the buffer (not to all node names in source
  1976. file).
  1977.  
  1978. Optional second arg is topic description; with prefix arg if
  1979. interactive, prompt for topic description.
  1980.  
  1981. If temporary main menu buffer exists, default topic description is
  1982. description line in the menu.  (Type \\[para-directory] to generate a
  1983. main menu buffer if it does not exist.\)"
  1984.   
  1985. ;;; Format of recently visited nodes buffer is the following:
  1986. ;;; 
  1987. ;;; "Create Files and Nodes"
  1988. ;;; "Movement Commands"
  1989. ;;; "Shortcut Commands"
  1990. ;;; "Para Mode Commands"
  1991.   
  1992.   (interactive
  1993.    (let ((default 
  1994.            (save-excursion
  1995.              (beginning-of-line)
  1996.              (re-search-forward "^\"\\([^\"]+\\)\"$" nil t)
  1997.              (buffer-substring (match-beginning 1) (match-end 1))))
  1998.          (description "")
  1999.          completions
  2000.          node-name)
  2001.      (save-excursion              ; create alist for completing-read
  2002.        (goto-char (point-min))
  2003.        (while (re-search-forward "^\"\\([^\"]+\\)\"$" nil t)
  2004.          ;; make a list each of element of which is \("name" . position\)
  2005.          (setq completions (cons (cons (buffer-substring
  2006.                                         (match-beginning 1)
  2007.                                         (match-end 1))
  2008.                                        (match-beginning 1))
  2009.                                  completions))))
  2010.      (setq node-name
  2011.            (let ((completion-ignore-case t))
  2012.              (completing-read
  2013.               (if default
  2014.                   (format "Node name (default %s): " default)
  2015.                 "Node name: ")
  2016.               completions nil t)))
  2017.      (if (string= node-name "") (setq node-name default))
  2018.      (if current-prefix-arg
  2019.          (setq description
  2020.                (read-string
  2021.                 "Topic description (end with RET): " 
  2022.                 (if (get-buffer para-main-menu-buffer-name)
  2023.                     (save-excursion
  2024.                       (set-buffer para-main-menu-buffer-name)
  2025.                       (goto-char (point-min))
  2026.                       (if (search-forward node-name nil t)
  2027.                           (para-main-menu-buffer-copy-description
  2028.                            (point-max))))))))
  2029.      (list node-name description)))
  2030.   (pop-to-buffer para-current-buffer)
  2031.   (if (string= "" topic-description)
  2032.       (insert (format "@xref{%s}." reference))
  2033.     (insert (format "@xref{%s, , %s}." reference topic-description))))
  2034.  
  2035.  
  2036. ;;; Movement commands with `C-c C-p' prefix: top, next, prev, etc.
  2037.  
  2038. ;     C-c C-p C-b     para-beginning
  2039. ;     C-c C-p C-<     para-top-node
  2040. ;     C-c C-p C->     para-final
  2041.  
  2042. ;     C-c C-p C-u     para-up
  2043. ;     C-c C-p C-p     para-prev
  2044. ;     C-c C-p C-n     para-next
  2045.  
  2046. ;     C-c C-p C-[     para-goto-previous-node-in-sequence
  2047. ;     C-c C-p C-]     para-goto-next-node-in-sequence
  2048.  
  2049. ;     C-c C-p RET     para-menu
  2050. ;     C-c C-p C-l     para-last
  2051. ;     C-c C-p C-g     para-goto
  2052. ;     C-c C-p C-f     para-follow
  2053.  
  2054. ;;; Basic movement commands: top, next, prev, etc.
  2055.  
  2056. (defun para-beginning ()
  2057.   "Go to the very beginning of the file (before a `Top' node)."
  2058.   ;;; Does not handle include files.
  2059.   (interactive)
  2060.   (widen)
  2061.   (goto-char (point-min))
  2062.   (setq para-history
  2063.         (cons (save-excursion (para-extract-pointer 'next)) para-history)))
  2064.  
  2065. (defun para-top-node ()
  2066.   "Go to the `Top' node."
  2067.   (interactive)
  2068.   (if (not (para-goto "top"))
  2069.       (error "`Top' node not found.")))
  2070.  
  2071. (defun para-final ()
  2072.   "Go to the last node in the Para file."
  2073.   ;;; Does not handle include files.
  2074.   (interactive)
  2075.   (widen)
  2076.   (goto-char (point-max))
  2077.   (re-search-backward "^@node")
  2078.   (end-of-line)
  2079.   (para-narrow-to-node)
  2080.   (beginning-of-line)
  2081.   (setq para-history
  2082.         (cons (texinfo-copy-node-name)
  2083.               para-history)))
  2084.  
  2085. (defun para-up ()
  2086.   "Go to the superior node of this node."
  2087.   (interactive)
  2088.   (if (not (para-goto (para-extract-pointer 'up)))
  2089.       (error "`Up' node not found.")))
  2090.  
  2091. (defun para-prev (&optional arg)
  2092.   "Go to the previous node of this node.
  2093. With optional arg (prefix if interactive) go to the previous node in
  2094. sequence, regardless of its hierarcichal level or type."
  2095.   (interactive "P")
  2096.   (if arg
  2097.       (para-goto (para-previous-node-in-sequence))
  2098.     (if (not (para-goto (para-extract-pointer 'prev)))
  2099.         (error "`Previous' node not found."))))
  2100.  
  2101. (defun para-next (&optional arg)
  2102.   "Go to the next node of this node.
  2103. With optional arg (prefix if interactive) go to the next node in
  2104. sequence, regardless of its hierarcichal level or type."
  2105.   (interactive "P")
  2106.   (if arg
  2107.       (para-goto (para-next-node-in-sequence))
  2108.     (if (not (para-goto (para-extract-pointer 'next)))
  2109.       (error "`Next' node not found."))))
  2110.  
  2111. (defun para-last ()
  2112.   "Go back to the last node visited."
  2113.   (interactive)
  2114.   (or para-history
  2115.       (error "This is the first para node you looked at"))
  2116.   (let ((node-name (car (cdr para-history))))
  2117.     (if (para-goto node-name)
  2118.         (setq para-history (cdr (cdr para-history)))
  2119.       (error "Node not found: %s " node-name))))
  2120.  
  2121. (defun para-extract-pointer (next-prev-up)
  2122.   "Return name of   `Next', `Previous', or `Up' pointer as a string."
  2123.   ;; only argument `next-prev-up' is  'next, 'previous, or 'up
  2124.   (or (looking-at "^@node")
  2125.       (re-search-backward "^@node"  nil 'move-to-limit))
  2126.   (widen)
  2127.   (save-excursion
  2128.   ;; done this ugly way because of troubles with match-data when
  2129.   ;; trying to record all the matches for the next, prev and up
  2130.   ;; pointers and then using match-beginning and match-end to extract
  2131.   ;; desired name.
  2132.   (cond ((eq next-prev-up 'next) 
  2133.          (if (not (looking-at "^@node"))            ; not within a node
  2134.              (para-next-node-in-sequence)
  2135.            ;; else within a node
  2136.            ;; search for end of `next' nodename
  2137.            (if (re-search-forward (concat 
  2138.                                    "^@node"
  2139.                                    "[ \t]*[^,]*[ \t]*,"     
  2140.                                    "[ \t]*\\([^,]*\\)[ \t]*,") nil t)
  2141.                (buffer-substring
  2142.                 (match-beginning 1)
  2143.                 (progn (skip-chars-backward ", \t\n") (point)))
  2144.              ;; else
  2145.              (error "Next node not found!"))))
  2146.         
  2147.         ((eq next-prev-up 'prev) 
  2148.          ;; search for end of `previous' nodename
  2149.          (if (re-search-forward (concat 
  2150.                                  "^@node"
  2151.                                  "[ \t]*[^,]*[ \t]*,"               ; nodename
  2152.                                  "[ \t]*[^,]*[ \t]*,"               ; `Next' 
  2153.                                  "[ \t]*\\([^,]*\\)[ \t]*,") nil t) ; `Prev'
  2154.              (buffer-substring
  2155.               (match-beginning 1)
  2156.               (progn (skip-chars-backward ", \t\n") (point)))
  2157.            ;; else
  2158.            (error "Previous node not found!")))
  2159.         
  2160.         ((eq next-prev-up 'up) 
  2161.          ;; search for end of `up' nodename
  2162.          (if (re-search-forward (concat 
  2163.                                  "^@node"
  2164.                                  "[ \t]*[^,]*[ \t]*,"               ; nodename
  2165.                                  "[ \t]*[^,]*[ \t]*,"               ; `Next'
  2166.                                  "[ \t]*[^,]*[ \t]*,"               ; `Prev'
  2167.                                  "[ \t]*\\([^,\n]*\\)"              ; `Up'
  2168.                                  "[ \t]*$") nil t)
  2169.              (buffer-substring
  2170.               (match-beginning 1)
  2171.               (progn (skip-chars-backward ", \t\n") (point)))
  2172.            ;; else
  2173.            (error "Up node not found!"))))))
  2174.  
  2175. (defun para-goto-next-node-in-sequence ()
  2176.   "Go to the next node in buffer regardless of its hierarchical level.
  2177. This is an interface to the function `para-next-node-in-sequence'."
  2178.   (interactive)
  2179.   (para-goto (para-next-node-in-sequence)))
  2180.  
  2181. (defun para-goto-previous-node-in-sequence ()
  2182.   "Go to the previous node in buffer regardless of its hierarchical level.
  2183. This is an interface to the function `para-previous-node-in-sequence'."
  2184.   (interactive)
  2185.   (para-goto (para-previous-node-in-sequence)))
  2186.  
  2187. (defun para-follow (reference)
  2188.   "Follow REFERENCE to the node it refers to.
  2189. REFERENCE may include a filename or be an abbreviation of the reference name."
  2190.   (interactive
  2191.    (list
  2192.     (let ((default 
  2193.             (save-excursion
  2194.               (beginning-of-line)
  2195.               (if (re-search-forward  "@p?x?ref{[ \t]*\\([^,}]*\\)" nil t)
  2196.                   (buffer-substring (match-beginning 1) (match-end 1))
  2197.                 (error "No cross-reference in this node"))))
  2198.           completions
  2199.           nodename
  2200.           filename
  2201.           current-point
  2202.           i)
  2203.       (save-excursion
  2204.         (goto-char (point-min))
  2205.         (while
  2206.             ;; search for cross reference
  2207.             (re-search-forward "@p?x?ref{[ \t]*\\([^,}]*\\)" nil t)
  2208.           (setq current-point (point))
  2209.           (setq nodename
  2210.                 (buffer-substring
  2211.                  (match-beginning 1)
  2212.                  (progn (skip-chars-backward " \t\n") (point))))
  2213.           
  2214.           ;; remove extraneous characters from nodename string
  2215.           (while (setq i (string-match "[ \n\t]+" nodename i))
  2216.             (setq nodename (concat (substring nodename 0 i) " "
  2217.                                    (substring nodename (match-end 0))))
  2218.             (setq i (1+ i)))
  2219.           
  2220.           (skip-chars-forward " \t\n")
  2221.           (if (looking-at "}")        ; no filename entry
  2222.               (setq filename nil)
  2223.             ;; else not looking at a closing brace
  2224.             
  2225.             ;; possibilities:  is a two, three, four, or five entry xref
  2226.             ;; set up for search 
  2227.             (re-search-backward "@p?x?ref{" nil t)
  2228.             
  2229.             (cond (;; search for xref ending with second entry
  2230.                    (re-search-forward "@p?x?ref{[^,]*,[^,]*}" nil t)
  2231.                    (setq filename nil))
  2232.                   ;; search for xref ending with third entry
  2233.                   ((re-search-forward "@p?x?ref{[^,]*,[^,]*,[^,]*}" nil t)
  2234.                    (setq filename nil))
  2235.                   ;; search for xref ending with filename \(fourth entry\)
  2236.                   ((re-search-forward
  2237.                     "@p?x?ref{[^,]*,[^,]*,[^,]*,\\([^,]*\\)}" nil t)
  2238.                    (setq filename 
  2239.                          (buffer-substring
  2240.                           (progn
  2241.                             (goto-char (match-beginning 1))
  2242.                             (skip-chars-forward " \t\n")
  2243.                             (point))
  2244.                           (progn
  2245.                             (goto-char (match-end 1))
  2246.                             (skip-chars-forward " \t\n")
  2247.                             (point)))))
  2248.                   ;; else look for xref ending in manual name entry
  2249.                   ((re-search-forward
  2250.                     "@p?x?ref{[^,]*,[^,]*,[^,]*,\\([^,]*\\)\\(,[^,]+\\)}"
  2251.                     nil t)
  2252.                    (setq filename 
  2253.                          (buffer-substring
  2254.                           (progn
  2255.                             (goto-char (match-beginning 1))
  2256.                             (skip-chars-forward " \t\n")
  2257.                             (point))
  2258.                           (progn
  2259.                             (goto-char (match-end 1))
  2260.                             (skip-chars-forward " \t\n")
  2261.                             (point)))))
  2262.                   (t (setq filename nil))))
  2263.           (if (assoc nodename completions)
  2264.               nil
  2265.             (setq completions (cons (cons nodename filename) completions)))
  2266.           (goto-char current-point)))
  2267.       
  2268.  
  2269.       (cond (completions
  2270.              (let ((completion-ignore-case t))
  2271.                (setq reference
  2272.                      (completing-read
  2273.                       (if default
  2274.                           (format "Follow cross ref to (default %s): " default)
  2275.                         "Follow cross ref to: ") 
  2276.                       completions nil t)))
  2277.              (if (string= reference "") (setq reference default))
  2278.              
  2279.              (if (cdr (assoc reference completions))
  2280.                  (setq filename
  2281.                        (read-from-minibuffer
  2282.                         "Go to cross reference in file: "
  2283.                         (cdr (assoc reference completions))))))
  2284.  
  2285.             (t (error "No cross-reference in this node")))
  2286.       (and filename (setq filename (concat "(" filename ")")))
  2287.       (concat filename reference))))
  2288.  
  2289.   (para-goto reference))
  2290.  
  2291.  
  2292. ;;; Regular Expression Search 
  2293.  
  2294. (defvar para-last-search nil
  2295.   "Default regexp for para-search command to search for.")
  2296.  
  2297. (defun para-search (regexp)
  2298.   "Search for REGEXP, starting from point, and select node it's found in."
  2299.   (interactive "sSearch (regexp): ")
  2300.   (if (equal regexp "")
  2301.       (setq regexp para-last-search)
  2302.     (setq para-last-search regexp))
  2303.   
  2304.   (let ((this-node para-current-node)
  2305.     found)
  2306.     (save-excursion
  2307.       (save-restriction
  2308.     (widen)
  2309.     (re-search-forward regexp)
  2310.     (setq found (point))))
  2311.     (widen)
  2312.     (goto-char found)
  2313.     (para-narrow-to-node)
  2314.     ;; para-narrow-to-node specifies value of para-current-node
  2315.     (or (equal this-node para-current-node)
  2316.         (setq para-history (cons para-current-node para-history)))
  2317.     (para-set-mode-line)))
  2318.  
  2319.  
  2320. ;;; Name of next or previous node in strict sequence
  2321.  
  2322. (defun para-next-node-in-sequence ()
  2323.   "Return name of next node in buffer regardless of its hierarchical level."
  2324.   (interactive)
  2325.   (widen)
  2326.   (end-of-line) ; to skip past `@node' at beginning of node.
  2327.   (if (not (re-search-forward "^@node" nil t))
  2328.       (progn (beginning-of-line)
  2329.              (para-narrow-to-node)
  2330.              (error "Next node not found!"))
  2331.     (beginning-of-line)
  2332.     (let ((nodename (texinfo-copy-node-name)))
  2333.       (or nodename
  2334.           (error "No node name found for Next node!")))))
  2335.  
  2336. (defun para-previous-node-in-sequence ()
  2337.   "Go to the previous node in buffer regardless of its hierarchical level."
  2338.   (interactive)
  2339.   (para-narrow-to-node)  ; so back search is not stuck at current node
  2340.   (goto-char (point-min))
  2341.   (widen)
  2342.   (if (not (re-search-backward "^@node" nil t))
  2343.       (progn (beginning-of-line)
  2344.              (para-narrow-to-node)
  2345.              (error "Previous node not found!"))
  2346.     (let ((nodename (texinfo-copy-node-name)))
  2347.       (or nodename
  2348.           (error "No node name found for Previous node!")))))
  2349.  
  2350.  
  2351. ;;; Single keystroke Info commands
  2352.  
  2353. (defun para-@ (key)
  2354.   "Provide Info-like commands when point in upper-left or buffer read-only.
  2355. In a writable buffer when point is not in the upper-left corner, keys 
  2356. self-insert."
  2357.   (interactive "p")
  2358.   (if (and (not buffer-read-only)
  2359.            (pos-visible-in-window-p (1- (point))))
  2360.       (progn
  2361.         (self-insert-command key)
  2362.         (if (<= fill-column (current-column))
  2363.             (if auto-fill-hook
  2364.                 (funcall auto-fill-hook)
  2365.               nil)))
  2366.     
  2367.     (let* ((this-key (aref (this-command-keys) 0)))
  2368.       (call-interactively
  2369.        (cond ((= this-key ?g)    'para-goto-node)
  2370.              ((= this-key ?<)    'para-top-node)
  2371.              ((= this-key ?>)    'para-final)
  2372.              ((= this-key ?\[)   'para-goto-previous-node-in-sequence)
  2373.              ((= this-key ?\])   'para-goto-next-node-in-sequence)
  2374.              ((= this-key ? )    'para-scroll-up)
  2375.          ((= this-key ?\^?)  'para-scroll-down)
  2376.              ((and (<= ?0 this-key) (<= this-key ?9))
  2377.               (cdr (assoc
  2378.                     this-key
  2379.                     (cdr (assoc 16  (cdr (assoc 3 para-mode-map)))))))
  2380.              (t (cdr (assoc
  2381.                       (- this-key ?`)
  2382.                       (cdr (assoc 16 (cdr (assoc 3 para-mode-map))))))))))))
  2383.  
  2384. (defun para-scroll-up (arg)
  2385.   "Scroll text of current window upward ARG lines.
  2386. Keep point in same relative position in window."
  2387.   (interactive "P")
  2388.   (let ((current-relative-position (- (window-point) (window-start))))
  2389.     (scroll-up arg)
  2390.     (goto-char (+ (window-start) current-relative-position))))
  2391.  
  2392. (defun para-scroll-down (arg)
  2393.   "Scroll text of current window downward ARG lines.
  2394. Keep point in same relative position in window."
  2395.   (interactive "P")
  2396.   (let ((current-relative-position (- (window-point) (window-start))))
  2397.     (scroll-down arg)
  2398.     (goto-char (+ (window-start) current-relative-position))))
  2399.  
  2400.  
  2401. ;;; Index entry commands:  @cindex, @findex, etc.
  2402.  
  2403. ;; Must redefine each index command to use `para-index' since
  2404. ;; `texinfo-index' deletes the index line after reading it.
  2405. ;; Hence the lack of shared code.
  2406.  
  2407. (put 'vindex 'para-format 'para-format-vindex)
  2408. (defun para-format-vindex () (para-index 'para-vindex))
  2409.  
  2410. (put 'cindex 'para-format 'para-format-cindex)
  2411. (defun para-format-cindex () (para-index 'para-cindex))
  2412.  
  2413. (put 'findex 'para-format 'para-format-findex)
  2414. (defun para-format-findex () (para-index 'para-findex))
  2415.  
  2416. (put 'pindex 'para-format 'para-format-pindex)
  2417. (defun para-format-pindex () (para-index 'para-pindex))
  2418.  
  2419. (put 'tindex 'para-format 'para-format-tindex)
  2420. (defun para-format-tindex () (para-index 'para-tindex))
  2421.  
  2422. (put 'kindex 'para-format 'para-format-kindex)
  2423. (defun para-format-kindex () (para-index 'para-kindex))
  2424.  
  2425. (defun para-index (indexvar)
  2426.   (let ((arg (texinfo-parse-expanded-arg)))
  2427.     (set indexvar
  2428.      (cons (list arg (para-current-node))
  2429.            (symbol-value indexvar)))))
  2430.  
  2431. (defconst para-indexvar-alist
  2432.   '(("cp" . para-cindex)
  2433.     ("fn" . para-findex)
  2434.     ("vr" . para-vindex)
  2435.     ("tp" . para-tindex)
  2436.     ("pg" . para-pindex)
  2437.     ("ky" . para-kindex)))
  2438.  
  2439.  
  2440. ;;; Define indices:  @defindex   @defcodeindex
  2441.  
  2442. (put 'defindex 'para-format 'para-format-defindex)
  2443. (put 'defcodeindex 'para-format 'para-format-defindex)
  2444. (defun para-format-defindex ()
  2445.   (let* ((index-name (texinfo-parse-line-arg)) ; eg: `aa'
  2446.          (indexing-command (intern (concat index-name "index")))
  2447.          (index-formatting-command      ; eg: `para-format-aaindex'
  2448.           (intern (concat "para-format-" index-name "index")))
  2449.          (index-alist-name              ; eg: `para-aaindex'
  2450.           (intern (concat "para-" index-name "index"))))
  2451.  
  2452.     (set index-alist-name nil)
  2453.  
  2454.     (put indexing-command               ; eg, aaindex
  2455.          'para-format
  2456.          index-formatting-command)      ; eg, para-format-aaindex
  2457.  
  2458.     ;; eg: "aa" . para-aaindex
  2459.     (or (assoc index-name para-indexvar-alist)
  2460.         (setq para-indexvar-alist
  2461.               (cons
  2462.                (cons index-name
  2463.                      index-alist-name)
  2464.                para-indexvar-alist)))
  2465.  
  2466.     (fset index-formatting-command
  2467.           (list 'lambda 'nil
  2468.                 (list 'para-index 
  2469.                       (list 'quote index-alist-name))))))
  2470.  
  2471.  
  2472. ;;; Merge indices: @synindex   @syncodeindex
  2473.  
  2474. (put 'synindex 'para-format 'para-format-synindex)
  2475. (put 'syncodeindex 'para-format 'para-format-synindex)
  2476.  
  2477. (defun para-format-synindex ()
  2478.   (let* ((args (texinfo-parse-line-arg))
  2479.          (second (cdr (read-from-string args)))
  2480.          (joiner (symbol-name (car (read-from-string args))))
  2481.          (joined (symbol-name (car (read-from-string args second)))))
  2482.  
  2483.     (if (assoc joiner para-short-index-cmds-alist)
  2484.         (put
  2485.           (cdr (assoc joiner para-short-index-cmds-alist))
  2486.          'para-format
  2487.          (or (cdr (assoc joined para-short-index-format-cmds-alist))
  2488.              (intern (concat "para-format-" joined "index"))))
  2489.       (put
  2490.        (intern (concat joiner "index"))
  2491.        'para-format
  2492.        (or (cdr(assoc joined para-short-index-format-cmds-alist))
  2493.            (intern (concat "para-format-" joined "index")))))))
  2494.  
  2495. (defconst para-short-index-cmds-alist
  2496.   '(("cp" . cindex)
  2497.     ("fn" . findex)
  2498.     ("vr" . vindex)
  2499.     ("tp" . tindex)
  2500.     ("pg" . pindex)
  2501.     ("ky" . kindex)))
  2502.  
  2503. (defconst para-short-index-format-cmds-alist
  2504.   '(("cp" . para-format-cindex)
  2505.     ("fn" . para-format-findex)
  2506.     ("vr" . para-format-vindex)
  2507.     ("tp" . para-format-tindex)
  2508.     ("pg" . para-format-pindex)
  2509.     ("ky" . para-format-kindex)))
  2510.  
  2511.  
  2512. ;;; Print index: @printindex
  2513.  
  2514. (put 'printindex 'para-format 'para-format-printindex)
  2515.  
  2516. (defun para-format-printindex ()
  2517.   (let ((indexelts (symbol-value
  2518.             (cdr (assoc (texinfo-parse-line-arg)
  2519.                 para-indexvar-alist))))
  2520.     opoint)
  2521.     (insert "\n@ignore\n* Menu:\n\n")
  2522.     (setq opoint (point))
  2523.     (para-print-index nil indexelts)
  2524.  
  2525.     (if (eq system-type 'vax-vms)
  2526.         (texinfo-sort-region opoint (point))
  2527.       (shell-command-on-region opoint (point) "sort -fd" 1))
  2528.         (insert "\n@end ignore\n")))
  2529.  
  2530. (defun para-print-index (file indexelts)
  2531.   (while indexelts
  2532.     (if (stringp (car (car indexelts)))
  2533.     (insert "* " (car (car indexelts))
  2534.         ": " (if file (concat "(" file ")") "")
  2535.         (nth 1 (car indexelts)) ".\n")
  2536.       ;; index entries from @include'd file
  2537.       (para-print-index (nth 1 (car indexelts))
  2538.                (nth 2 (car indexelts))))
  2539.     (setq indexelts (cdr indexelts))))
  2540.  
  2541.  
  2542. ;;; Insert index into Para mode file (interactive command)
  2543.  
  2544. (defun para-insert-index ()
  2545.   "Insert index at @printindex command in Para mode file."
  2546.   (interactive)
  2547.   (require 'texinfmt)
  2548.   (widen)
  2549.   (let (para-command-name
  2550.         texinfo-command-start
  2551.         texinfo-command-end
  2552.         texinfo-last-node               ; Texinfo mode variable
  2553.         para-vindex
  2554.         para-findex
  2555.         para-cindex
  2556.         para-pindex
  2557.         para-tindex
  2558.         para-kindex)
  2559.     
  2560.     (goto-char (point-min))
  2561.     (while (re-search-forward "^@\\w+index" nil t)
  2562.       (forward-word -1)
  2563.       ;; @ is followed by a command-word; find the end of the word.
  2564.       (setq texinfo-command-start (point))
  2565.       (forward-word 1)
  2566.       (setq texinfo-command-end (point))
  2567.       ;; Call the handler for this command.
  2568.       (setq para-command-name
  2569.             (intern (buffer-substring texinfo-command-start
  2570.                                       texinfo-command-end)))
  2571.       (let ((cmd (get para-command-name 'para-format)))
  2572.         (if cmd (funcall cmd)
  2573.           (error "Para mode cannot handle \"%s\"."
  2574.                  (buffer-substring
  2575.                   texinfo-command-start 
  2576.                   texinfo-command-end)))))))
  2577.  
  2578.  
  2579. ;;; Create index entries (interactive commands)
  2580.  
  2581. (defun para-index-function (function &optional where)
  2582.   "Insert entry for function index at end of paragraph.
  2583. Interactively, offer first symbol following point within paragraph
  2584. that is enclosed by braces of @code command.  With prefix arg, insert
  2585. entry at point \(no default offered\)."
  2586.   (interactive (para-index-what-and-where-utility))
  2587.   (if (eq where 'end-para)  (forward-paragraph 1))
  2588.   (insert "@findex " function "\n"))
  2589.  
  2590. (defun para-index-variable (variable &optional where)
  2591.   "Insert entry for variable index at end of paragraph.
  2592. Interactively, offer first symbol following point within paragraph
  2593. that is enclosed by braces of @code command.  With prefix arg, insert
  2594. entry at point \(no default offered\)."
  2595.  
  2596.   (interactive (para-index-what-and-where-utility))
  2597.   (if (eq where 'end-para)  (forward-paragraph 1))
  2598.     (insert "@vindex " variable "\n"))
  2599.  
  2600. (defun para-index-program (program &optional where)
  2601.   "Insert entry for program index at end of paragraph.
  2602. Interactively, offer first symbol following point within paragraph
  2603. that is enclosed by braces of @code command.  With prefix arg, insert
  2604. entry at point \(no default offered\)."
  2605.   
  2606.   (interactive (para-index-what-and-where-utility))
  2607.   (if (eq where 'end-para)  (forward-paragraph 1))
  2608.   (insert "@pindex " program "\n"))
  2609.  
  2610. (defun para-index-datatype (datatype &optional where)
  2611.   "Insert entry for datatype index at end of paragraph.
  2612. Interactively, offer first symbol following point within paragraph
  2613. that is enclosed by braces of @code command.  With prefix arg, insert
  2614. entry at point \(no default offered\)."
  2615.   
  2616.   (interactive (para-index-what-and-where-utility))
  2617.   (if (eq where 'end-para)  (forward-paragraph 1))
  2618.   (insert "@tindex " program "\n"))
  2619.  
  2620. (defun para-index-keystroke (keystrokes &optional where)
  2621.   "Insert entry for keystroke index at end of paragraph.
  2622. Interactively, offer default:
  2623.  
  2624.     1. If point is at beginning of an @item or @itemx line,
  2625.        offer rest of that line.
  2626.  
  2627.     2. Else, offer first symbol following point within paragraph
  2628.        that is enclosed by braces of @kbd command.
  2629.  
  2630. With prefix arg, insert entry at point \(no default offered\)."
  2631.   
  2632.   (interactive
  2633.    (let (keystrokes where)
  2634.      (if current-prefix-arg
  2635.          (setq keystrokes (read-from-minibuffer "Keystrokes: ")
  2636.                where 'here)
  2637.        (let((default-keystrokes
  2638.               (if (looking-at "@itemx? \\(.*\\)$")
  2639.                   (buffer-substring (match-beginning 1) (match-end 1))
  2640.                 
  2641.                 (if (re-search-forward "@kbd\\s(\\(\\S)+\\)\\s)")
  2642.                     (buffer-substring (match-beginning 1) (match-end 1))
  2643.                   ""))))
  2644.          
  2645.          (setq keystrokes
  2646.                (read-from-minibuffer 
  2647.                 "Keystrokes: "
  2648.                 (if default-keystrokes default-keystrokes ""))
  2649.                where 'end-para)))
  2650.      
  2651.      (list keystrokes where)))
  2652.   (if (eq where 'end-para)  (forward-paragraph 1))
  2653.   (insert "@kindex " keystrokes "\n"))
  2654.  
  2655. (defun para-index-concept (concept &optional where)
  2656.   "Insert entry for concept index at end of paragraph.
  2657. Offer word following point as default; with numeric prefix arg, offer
  2658. that many words following point as default.  With prefix arg (not a
  2659. numeric prefix arg), insert entry at point \(no default offered\).
  2660. Non-interactively, first arg CONCEPT is string; optional second arg
  2661. WHERE is either symbol 'here or symbol 'end-para."
  2662.  
  2663.   (interactive
  2664.    (let (concept where how-many)
  2665.      (cond ((and (listp current-prefix-arg)
  2666.                  (eq 4 (prefix-numeric-value current-prefix-arg)))
  2667.             (setq where 'here))
  2668.            ((prefix-numeric-value current-prefix-arg) 
  2669.             (setq how-many (prefix-numeric-value current-prefix-arg)
  2670.                   where 'end-para))
  2671.            (t (setq how-many 1 where 'end-para)))
  2672.      (if (eq where 'end-para)
  2673.          (let((default-concept
  2674.                 (buffer-substring
  2675.                  (save-excursion (skip-chars-forward " \t") (point))
  2676.                  (save-excursion (forward-word how-many) (point)))))
  2677.            (setq concept (read-from-minibuffer 
  2678.                           "Concept: " (if default-concept default-concept
  2679.                                         ""))))
  2680.        (setq concept (read-from-minibuffer 
  2681.                       "Concept: ")))
  2682.      (list concept where)))
  2683.   
  2684.   (if (eq where 'end-para)  (forward-paragraph 1))
  2685.   (insert "@cindex " concept "\n"))
  2686.  
  2687.  
  2688. ;;; Index utility functions
  2689. ;;; para-current-node, para-index-what-and-where-utility 
  2690.  
  2691. (defun para-current-node ()
  2692.   "Return name of current node at or preceding point."
  2693.   (save-excursion
  2694.     (if (or (looking-at "^@node")
  2695.             (re-search-backward "^@node"  nil 'move-to-limit))
  2696.         ;; point is within a node
  2697.         (progn
  2698.           (re-search-forward "@node[ \t]*\\<\\([^,]*\\),")
  2699.           (buffer-substring (match-beginning 1) (match-end 1)))
  2700.       ;; else node not found
  2701.       (error "Node not found."))))
  2702.  
  2703. (defun para-index-what-and-where-utility ()
  2704.   "Utility used by para-index-function and others."
  2705.   (let (what where)
  2706.     (if current-prefix-arg
  2707.         (setq what (read-from-minibuffer "Entry: ")
  2708.               where 'here)
  2709.       (let((default-what
  2710.              (if (re-search-forward
  2711.                   "@code\\s(\\(\\S)+\\)\\s)"
  2712.                   (save-excursion (forward-paragraph 1) (point))
  2713.                   t)
  2714.                  (buffer-substring
  2715.                   (match-beginning 1) (match-end 1)))))
  2716.         (setq what (read-from-minibuffer 
  2717.                         "Entry: " (if default-what default-what ""))
  2718.                where 'end-para)))
  2719.     (list what where)))
  2720.  
  2721.  
  2722. (message "Loading Para mode ... done ")
  2723. (provide 'para)
  2724.  
  2725.  
  2726.  
  2727. ;;; Bob only: site specific key rebinding
  2728.  
  2729. ; `C-c C-x' is the prefix key for Para indexing.
  2730. ; Redefine para-mode-map to use control keys in order to avoid
  2731. ; conflict with Bob's keybindings for edebug.
  2732.  
  2733. (define-key para-mode-map "\C-c\C-x\C-c" 'para-index-concept)
  2734. (define-key para-mode-map "\C-c\C-x\C-f" 'para-index-function)
  2735. (define-key para-mode-map "\C-c\C-x\C-k" 'para-index-keystroke)
  2736. (define-key para-mode-map "\C-c\C-x\C-p" 'para-index-program)
  2737. (define-key para-mode-map "\C-c\C-x\C-t" 'para-index-datatype)
  2738. (define-key para-mode-map "\C-c\C-x\C-v" 'para-index-variable)
  2739.  
  2740. (define-key para-mode-map "\C-c\C-x\C-x" 'para-insert-index)